@azure-id/orc 0.55.2 → 0.56.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,2064 +1,2218 @@
1
- # Changelog
2
-
3
- All notable changes to ORC, newest first.
4
-
5
- The **latest release** is also summarised in the [README](README.md#changelog).
6
- This file is the full history, and it is the file `orc changelog` reads — that
7
- command prints only the entries **newer than the version you have installed**.
8
-
9
- Format: `### v<version> — <title> _(<date>)_`.
10
-
11
- ---
12
-
13
- ### v0.55.2 - a gate that is never probed is a gate that is always off _(2026-08-27)_
14
-
15
- **`/orc-quick` and `/orc-fast` documented the foreign-worker option and then
16
- never went and looked for it.** Both lanes carried the full `orc extra` slot
17
- contract - the menu line, the dispatch call, the failure path - but neither
18
- preflight ever RAN the probe that answers whether a position is held. orc-quick's
19
- Q0 said "read `log_dir` only, read no other key"; orc-fast's F0 had gates a, b
20
- and c and no extra step, while the F2 prose claimed the `extra:` line "joins the
21
- F0 preflight". So a user who armed `extra_enabled` and set
22
- `orc extra role set quick-executor ds/deepseek-chat` was still offered the two
23
- shipped Claude executors and nothing else, with no way to tell configuration
24
- from a bug.
25
-
26
- - **orc-quick Q0 gains one PROBE**, named as the single exception to
27
- "read no other key": `orc extra resolve --slot quick-executor --json`. One
28
- command answers the master gate, the position and the routing together, so the
29
- code-writing menu can render line 3. It is still an OPTION - never a default,
30
- never sticky, re-asked after a failure.
31
- - **orc-fast F0 gains gate `d`**, a probe rather than a gate:
32
- `orc extra resolve --slot fast-executor --json`. Resolved `extra` prints the
33
- P0 `extra:` line where the prose always said it would, naming the agent it
34
- displaces (`orc-executor-sonnet-4-6-high`); resolved `claude` prints nothing
35
- and never falls back - no row on a slot is an ANSWER, not a gap.
36
- - **`/orc-doc` was never affected.** Its targets are resolved by
37
- `docExtraResolve` inside `orc doc next`, so the CLI computes them and no
38
- preflight step can forget to ask. That is the shape the other two now borrow.
39
-
40
- No CLI change, no config key, no agent change.
41
-
42
- ### v0.55.1 ORC is on npm _(2026-08-27)_
43
-
44
- **ORC is published as [`@azure-id/orc`](https://www.npmjs.com/package/@azure-id/orc).**
45
- The GitHub tarball still works and nothing about the payload changed no skill,
46
- no agent, no CLI behaviour moved. This is the install path getting a name.
47
-
48
- - **`npm i -g @azure-id/orc`** is the install, and
49
- **`npm i -g @azure-id/orc@latest`** is the update. `orc upgrade` already
50
- fetched the newest package and then applied it, and it continues to;
51
- `orc upgrade --from @azure-id/orc` names npm explicitly.
52
- - **The GitHub tarball is the fallback now**, not the headline kept in the
53
- Quick start behind a fold for forks and for anyone pinning a branch.
54
- - **`orc update` is unchanged**: it re-copies the package you already have and
55
- never touches the network, so `npm i -g @azure-id/orc@latest && orc update`
56
- is the manual spelling of `orc upgrade`.
57
-
58
- ---
59
-
60
- ### v0.55.0 a score is what a band needs, and four lanes do not have one _(2026-08-26)_
61
-
62
- **A score is what a band needs, and four lanes do not have one.** `/orc-quick`,
63
- `/orc-fast`, `/orc-doc` and `/orc-wiki` pin an agent to a POSITION rather than
64
- scoring a task. `orc extra` routed them anyway by resolving the pinned agent's
65
- score band at both edges, which is arithmetic on a number nobody chose.
66
-
67
- It was wrong twice and dead once. A document set to `checker` resolved the
68
- **writer's** band for a role it was not routing. `/orc-wiki` asked for a role
69
- named `scanner` that `extra_roles` refuses by name, so that lane could never
70
- route however it was configured — `orc extra lanes` printed `claude` forever,
71
- with a reason that read like a user's choice. And `orc extra dispatch` required a
72
- `score` unconditionally, so **no non-scored dispatch had ever reached the bridge
73
- at all** not the fence, not the journal, not the spend log.
74
-
75
- - **`orc extra role` holds six POSITIONS**: `quick-executor` · `fast-executor` ·
76
- `doc-writer` · `doc-checker` · `wiki-scanner-deep` · `wiki-scanner-light`. One
77
- named position, one chosen `profile/model`, and **a row's presence is the
78
- arming**. `list` prints all six always an unrouted position keeps its slot
79
- and reads as the Claude agent it falls through to, because "I left the checker
80
- on Claude on purpose" and "there is no checker" must never look the same.
81
- - **A second resolver that never touches a band.** `orc extra resolve --slot
82
- <slot>` is the sibling of the score shape, same answer, same exit codes, and
83
- the Claude answer it carries is a **pinned NAME rather than an interval** —
84
- strictly more honest than what the scored half can offer. Nine hold-backs, each
85
- answered by name; a cited risk is never invented for a lane that has none.
86
- - **Precedence, one sentence for both shapes:** extra decides *whether* a Claude
87
- agent runs at all; `opus5_only` and the score tables only decide *which* Claude
88
- agent runs where extra did not take it. Under a taken slot `opus5_only` is **not
89
- consulted** and it stays fully live for every position with no row. `orc
90
- config list` and `orc config set` now name the taken POSITIONS beside the taken
91
- bands.
92
- - **The bridge accepts a slot.** Exactly one of `score` or `slot`; both is
93
- refused by name; `band` becomes `slot:<slot>` so the trace parser, the
94
- eight-field dedupe and `orc extra stats` are untouched and each position gets
95
- its own cost row for free. **Zero new engines, zero new dispatch paths, zero new
96
- agents** the fence, the cap, the credential triangle, the journal, the spend
97
- log and the resume ladder all come along unchanged.
98
- - **Per lane:** `/orc-doc` resolves each role against its OWN slot and `orc doc
99
- next` names the model per role before the wave (a document's voice is the
100
- deliverable); `/orc-wiki` prints its target beside the tier it already prints;
101
- `/orc-fast` names the agent it displaced in the F0 line; **`/orc-quick` gets a
102
- THIRD OPTION on its menu** — never a default, never sticky, re-asked after a
103
- failure, because that gate's whole premise is asking.
104
- - **`orc ui Extra ▸ Routing` grows a second ladder** below the bands, and
105
- **zero config keys were added** a second master gate, per-lane switches,
106
- `extra_quick_ask` and a per-slot model key were all considered and are written
107
- down as refused.
108
-
109
- ---
110
-
111
- ### v0.54.0 a failed dispatch is a POSITION, not a blank page _(2026-08-25)_
112
-
113
- **A worker on another model wrote six of seven lines and lost its connection.
114
- ORC sent the same task to Claude from scratch onto a file that was already
115
- two-thirds written.**
116
-
117
- `orc extra` had exactly one recovery move: re-dispatch the SAME slice to the
118
- Claude band. That move assumes the worktree is where the dispatch found it. **It
119
- usually is not.** The replacement executor's three plausible moves were all
120
- wrong: `Write` the file whole and discard work you already paid for · `Edit`
121
- against a stale mental model so `old_string` does not match and it improvises ·
122
- read first and then guess whether what is there is its own earlier work, a
123
- teammate's, or garbage. No field in the slice could have told it, and no field in
124
- the return contract could have carried it.
125
-
126
- **The registered token, sixth in its family:** `a lane that re-does work the
127
- worktree already contains` has broken this contract. It joins `a lane that
128
- answers its own interview question`, `a lane that picks its own favourite`, `a
129
- lane that fixes what it judged`, `a lane that picks its own council`, `a lane
130
- that reads its own document`, and `a lane that sends work off Claude without
131
- saying so`.
132
-
133
- - **THE JOURNAL IS THE CLI'S, AND IT IS WRITTEN BEFORE THE FIRST BYTE LEAVES THE
134
- MACHINE.** `.claude/orc/extra-journal/<task_id>/` a header carrying HEAD,
135
- `git status --short` in full and a hash plus a line count for every
136
- `declared_files` entry; a progress log appended as the dispatch runs; a result
137
- written beside the spend append. It is written by `orc extra dispatch` itself,
138
- which is the **fourth** time this repo has chosen a written-by-the-CLI fact
139
- over a relayed one (v0.32.0 narration, v0.49.5's hand-back page, v0.53.2's
140
- spend log). No lane writes it, no lane can forget it, and it is best effort by
141
- construction: a journal that cannot be written never takes the dispatch down.
142
- The header is the only record of what the repository looked like before a
143
- third party touched it, which is the only thing that makes a reconciliation
144
- possible at all.
145
- - **`orc extra reconcile <task_id>` — FREE, deterministic, and it runs before
146
- anything paid.** Five states, five exit codes (0 `resumable` · 1
147
- `nothing-to-resume` · 2 `no-journal` · 3 `complete` · 4 `in-flight`), and 0 is
148
- the answer the command exists to give rather than "healthy". Per declared file:
149
- `untouched` · `created` · `modified` · `deleted` · `reverted`, with line counts
150
- where they can be computed EXACTLY and `null` where they cannot **unknown is
151
- not zero**. Plus `touched_undeclared[]` (a fence breach, surfaced here because
152
- a crashed dispatch is exactly when the worktree delta never ran), the last
153
- recorded action, and the partial token vector.
154
- - **It deliberately does NOT decide whether a file is finished.** No brace
155
- counter, no truncation heuristic, no language sniffing /orc-doc's house-rule
156
- boundary verbatim: the CLI cannot parse intent, so it does not pretend to, and
157
- **a fake validator would be worse than none.** The checks that answer "is this
158
- done" already exist and are already engine-blind. Reconciliation's job is to
159
- point them at the right thing.
160
- - **ATTRIBUTION whose fault it was, with the evidence.** Five verdicts, each
161
- carrying a different correct recovery: `provider` · `network` · `local` ·
162
- `worker` · `orc`. **`network` HOLDS THE WAVE** a Claude fallback cannot
163
- succeed when the machine has no network, so falling back would be a second
164
- failure and a second cost for nothing. The two are told apart by ONE
165
- unauthenticated 3-second request on a path that has already failed, made only
166
- on the reasons that cannot be separated without it. `orc` is on the list on
167
- purpose: a report about a third party with no way to blame its own author is
168
- not a report anybody should trust — v0.53.3 was exactly an ORC bug that
169
- presented as a bad key.
170
- - **`orc extra resume-slice <task_id> --out <f>` composes the continuation, and
171
- the CLI owns the wording.** It is a NEW DISPATCH OF A DERIVED SLICE through the
172
- ordinary bridge zero new engines, zero new dispatch paths, **zero new
173
- agents** so the fence, the concurrency cap, the credential rules, the spend
174
- log and the worktree delta all come along unchanged. It **never widens
175
- `declared_files`**, **never moves `acceptance[]`**, **never moves the score**
176
- (a resume is not a discount), and **refuses on a drifted slice**, naming both
177
- hashes.
178
- - **Where a resume goes is DERIVED, never a config key.** Retryable → the same
179
- profile in a new session, up to `extra_resume_max`. Non-retryable → the Claude
180
- band, **still as a RESUME slice** which is what fixes the original bug: the
181
- Claude fallback stops being a from-scratch dispatch, which it should never have
182
- been. A key here would let somebody configure "always the same profile" and
183
- then wait out the cap × a 401.
184
- - **Six refusals, each NAMED, each writing NOTHING** (`not-resumable` ·
185
- `in-flight` · `reverted-file` · `slice-drifted` · `resume-cap` ·
186
- `resume-disabled`). **A live attempt is never resumed:** a dropped socket does
187
- not prove a provider stopped streaming, so a resume is gated on the pid being
188
- gone OR the lease having expired — and past the lease a live pid is treated as
189
- somebody else's process, stated as the honest bound it is rather than as proof.
190
- **A `reverted` declared file blocks and names the paths:** resuming on top of a
191
- possible destructive action is the one case where continuing is worse than
192
- starting over, and ORC does not get to make that call.
193
- - **Two new failure classes make the recovery choosable.** `stream-interrupted`
194
- (the connection was established and then died `unreachable` means it never
195
- opened, and those two want opposite recoveries) and `connection-lost-local`
196
- (the same, with the probe also failing). A taxonomy that returned one word for
197
- both could not pick either, which is why there was only ever one recovery.
198
- - **JOURNAL FIDELITY IS DECLARED PER ENGINE and never rendered stronger than it
199
- is.** `api` and `claude-shim` are `per-turn`; engine `cli` is
200
- `streamed-opaque` its child's stdout now goes to a FILE DESCRIPTOR rather
201
- than a buffer in a parent that dies, so a wall-clock kill leaves the bytes on
202
- disk and `output_file` stops being `null`. ORC captured them and did not
203
- interpret them, and **a gap that is not reported reads as a capability**.
204
- - **A killed dispatch's spend is recoverable.** `appendExtraSpend` runs after the
205
- engine returns, so a killed parent left real money invisible to every cost
206
- report the v0.53.2 hole through a different door. Reconcile writes the
207
- journal's running vector once, idempotently, as `recovered: true, complete:
208
- false`. **Measured is not unknown; unknown is not zero; a recovered vector is a
209
- FLOOR and says so.**
210
- - **Orphans are REPORTED at preflight and never resumed.** `orc extra preflight`
211
- lists every journal with a header, no result and an expired lease — and does
212
- **not** change its exit code, because an orphan is a finding, not a stop.
213
- Silently continuing a third party's half-finished write into somebody's
214
- repository is the same class of act as routing off Claude without saying so.
215
- - **Reliability becomes a MEASURED property of a profile.** `orc extra stats`
216
- gains per-profile `dispatches` · `failed` · `resumed` · `orphaned` · mean time
217
- to failure · the attribution split, and **below 10 dispatches there is no rate
218
- at all** — a percentage from three tries is noise with a percent sign on it.
219
- `orc extra doctor` gains `extra-orphan-dispatch` and `extra-profile-unreliable`
220
- (never below the floor). Both ABSENT counts are named.
221
- - **`orc ui Extra Recovery`** a sixth tab, not a tenth card. One row per
222
- journal, **expanded in place** (the Runs-row rule), and the free/paid line is
223
- visible: `reconcile` is a button, `resume-slice` is a copy-able command,
224
- because the panel never runs a lane. A row with nothing to show KEEPS ITS SLOT;
225
- `in-flight` renders as a refusal with its reason; prune is preview-then-apply
226
- and **names every directory**. Spending gains the reliability strip. Overview
227
- gets one line, only when there is something to say, and it never offers to
228
- continue anything.
229
- - **Two new config keys, and the four that were refused are written down.**
230
- `extra_resume` (`on`) and `extra_resume_max` (`2`) — nine keys became eleven.
231
- Deliberately NOT added: a key for where a resume goes, a key for the retry
232
- ladder (`extra_timeout_s` is already the budget), a key to disable the journal
233
- or its 30-day retention (**a record you can switch off is off on the run you
234
- needed it for**), and a key for the network probe. `extra_resume` is INERT in
235
- `/orc-quick`, announced at the agent gate.
236
- - **New trace verbs** `EXTRA resume` and `EXTRA orphan`, composed by the CLI and
237
- copied verbatim a resume that leaves no line cannot be counted by
238
- `orc extra stats` or `/orc-retro`. New mocked run: `mock-run/extra-recovery.md`.
239
-
240
- ---
241
-
242
- ### v0.53.4 the reload that dropped its own token _(2026-08-24)_
243
-
244
- **Every `orc update` from the panel ended on `This link is missing its session
245
- token.` — and the token was never missing.**
246
-
247
- v0.53.2 taught the server to hand itself over to a fresh process on the SAME
248
- port and the SAME token, so the URL in the address bar stays valid and the open
249
- tab only has to reload. That half worked. The reload did not: the panel strips
250
- `?t=` out of the visible URL at boot (`00-core.js`, so the token never lands in
251
- a screenshot or a pasted link), and the hand-over then called
252
- `location.reload()` which re-requests **the stripped address**. No `?t=`, no
253
- `x-orc-token` header on a document request, and the server correctly answered
254
- with the un-authenticated page. Deterministic, on every maintenance action that
255
- declares `restarts_ui`.
256
-
257
- - **A reload is not `location.reload()` here.** `reloadWithToken()` re-attaches
258
- the in-memory token and `location.replace()`s that URL. It is the only reload
259
- route in the panel, and a test fails on any bare `location.reload()` in
260
- `app.js` the stripping is deliberate, so the fix has to be the reload, not
261
- the strip.
262
- - Nothing about the server, the successor, the lock, the token generation or the
263
- `restarts_ui` declaration changed. The upgrade had already installed by the
264
- time the page broke; the user's recovery — `orc ui --stop` then `orc ui` — was
265
- producing a *new* token for a server that was already the new build.
266
-
267
- ---
268
-
269
- ### v0.53.3 — the key it never sent _(2026-08-24)_
270
-
271
- **A vaulted, verified, routed connection authenticated every wave with the wrong
272
- secret, and four separate green checks agreed it was fine.**
273
-
274
- `orc extra dispatch` resolved the credential by passing `inMemory:
275
- process.env.ORC_EXTRA_KEY` into `extraCredentialValue`, and that option
276
- short-circuited the vault branch **on its first line**. So whenever
277
- `ORC_EXTRA_KEY` was set in the environment a leftover from another profile,
278
- another provider, another day dispatch sent *that* value and never opened the
279
- vault at all. The profile's real, verified, vaulted key was never consulted.
280
-
281
- Only `dispatch` and `conform` passed that option. `ping`, `models --test` and
282
- `preflight` all resolved without it, opened the vault, and succeeded. Hence the
283
- part that made this expensive to find:
284
-
285
- ```
286
- orc extra doctor → nothing to report.
287
- orc extra list → dipkshit deepseek/api verified key vault
288
- orc extra preflight → dipkshit ok saved until 2027-08-19
289
- orc extra models dipkshit --test <model> → answered in 1866ms
290
- ```
291
-
292
- Four checks, each honest about the path it exercised, **none of them exercising
293
- the path a dispatch takes**. Then the wave died at HTTP 401 —
294
- `Your api key: ****w5f7 is invalid` pointing at the vaulted key the user had
295
- verified four minutes earlier, while the key ORC actually sent came from an
296
- environment variable the message never named. Nothing was written and nothing was
297
- billed; the run halted at F2 under `extra_on_failure: stop`.
298
-
299
- - **The two in-memory options were one option, and they are different facts.**
300
- `opts.inMemory` is an **explicit** key supplied for this invocation
301
- (`--key-stdin`) the key being tested and then stored, so it still wins.
302
- `opts.ambientKey` is a key found lying in the environment, and it is now what
303
- it was always written to be: the **unattended-wave fallback**, applying only to
304
- a vault that cannot be opened here (`extra_unlock: per-dispatch`, where nothing
305
- is cached on purpose). **A vault ORC can open always wins.**
306
- - **A passphrase in hand that the vault refuses is a real answer about the
307
- declared source,** not a reason to reach for a leftover variable. It returns the
308
- refusal rather than burning an attempt and then sending the wrong secret anyway.
309
- - **The return now reports the source it USED.** `credential.source` is one of
310
- `vault` · `env` · `ambient` · `memory` · `tool`, and it describes what happened
311
- rather than what the profile declares the two disagreed for a release, so the
312
- one field that could have named the bug confirmed the wrong story instead.
313
- `credential_override` is printed whenever the profile's declared source was not
314
- the one used, pass or fail: an override nobody was told about is the same class
315
- of silence as work leaving Claude with no `extra:` line.
316
- - **A 401 names the source that produced the rejected secret.** The provider's
317
- message describes what it saw; only ORC knows where that came from. It was a
318
- five-minute fix and a multi-step diagnosis.
319
-
320
- **`ORC_EXTRA_KEY` holds the KEY, and `orc extra keyhelp` said it was the
321
- passphrase.** For a vaulted profile it rendered a per-OS instruction to export
322
- `ORC_EXTRA_KEY="<your passphrase>"`into the exact variable a dispatch sends to
323
- the provider in an `Authorization` header. Following ORC's own instruction handed
324
- the secret that opens the vault to a third party. The block is gone. In its place
325
- the route **with a deadline on it** renders first (`orc extra session <name>
326
- --save --ttl 30`, the v0.52.0 design), then the variable, described as the key,
327
- with the warning that a passphrase must never go there. Nothing in ORC reads a
328
- passphrase from the environment, so `passphrase_env` is now always `null`.
329
-
330
- **One completions URL, and the probes speak it.** `ping` rung 2 and
331
- `models --test` hardcoded `{base}/chat/completions` while dispatch derived
332
- `{base}/v1/chat/completions` through `apiCompletionsUrl` and neither probe
333
- honoured a profile's `completions_path` at all. DeepSeek accepts both spellings,
334
- so this was not the 401; on a provider that accepts only one it produces a
335
- profile that verifies **green** and dispatches into a 404, which is the same lie
336
- wearing a different status code. Both probes now call the same builder.
337
-
338
- **And the unknown-model escape has to be about the model.** A 400/404/422 on the
339
- probe's invented model id was read as proof that the endpoint authenticated
340
- before declining the name — which is only true if the endpoint is the one it was
341
- aiming at. A gateway answering `Unknown request URL` with a 404 authenticated
342
- nothing. The rejection must now name the model asked for, or say something about
343
- a model/engine/deployment; otherwise the ping fails honestly instead of
344
- verifying. `verify_credential_source` records which credential earned the badge.
345
-
346
- **The fake provider was more permissive than the provider.** It answered a
347
- completion on **any** path, which is precisely why two probes could hardcode the
348
- wrong one for three releases with a green suite. It now serves exactly the path
349
- `apiCompletionsUrl` derives and 404s the rest the v0.53.0 rule, applied to the
350
- third surface in a row that broke on it.
351
-
352
- ---
353
-
354
- ### v0.53.2 the cost that was paid and never written down _(2026-08-24)_
355
-
356
- **Two foreign dispatches ran, cost real money, and every cost report read zero.**
357
-
358
- `orc extra dispatch` composes an `EXTRA …` trace line and hands it back for the
359
- lane to copy into a phase packet. That is a RELAY THROUGH A MODEL — the
360
- remembered-not-dispatched pattern this repo has already lost to twice and it
361
- broke in both directions on two graded runs of the same feature:
362
-
363
- - one wrote `EXTRA Codex/gpt-5.4-mini :: engine=cli …`, adding the trace's own
364
- `verb :: tail` separator, which the parser did not accept;
365
- - one dropped the line entirely and folded the token vector into a free-form
366
- `VERIFY` sentence.
367
-
368
- Both dispatches SUCCEEDED. `return.json` and `return-fast.json` were sitting in
369
- the run folder with complete four-kind vectors 27,029 / 0 / 159,616 / 1,895 for
370
- codex, 136 / 0 / 20,032 / 134 for opencode and a perfectly formed `trace_line`
371
- inside each. `orc extra stats` reported **0 dispatches from 2 traces**, `orc extra
372
- rates` had no pair to price, and `orc ui Extra Spending` read **`0 tasks
373
- sent`**. A cost report that reads zero when money was spent is worse than no
374
- report, because a zero gets believed.
375
-
376
- - **THE BRIDGE WRITES THE SPEND DOWN ITSELF.** Every dispatch appends one JSON
377
- object to `.claude/orc/extra-spend.jsonl` at the moment it holds the numbers
378
- profile, provider, model, engine, task, band, the four token kinds unblended,
379
- outcome, duration, the run it belonged to, and the `trace_line` it composed.
380
- The `RESUME.md` lesson from v0.49.5 applied to money: **the fact is recorded by
381
- the hand that computed it.** Best effort by construction a record that cannot
382
- be written never takes a dispatch down — and the dispatch says `spend_logged`
383
- either way, because a dispatch no cost report can see is worth one line now
384
- rather than a mystery later.
385
- - **The trace line is NOT retired, it is DEMOTED to the second source.** It is
386
- still the run's narrative and still what `/orc-retro` reads; it is no longer
387
- what the money depends on. The two are DEDUPED on the eight fields the line
388
- itself carries, so a lane that relays correctly is counted exactly once
389
- double-counting a correct relay would punish the behaviour the contract asks
390
- for.
391
- - **The parser now accepts the ` :: ` a trace writer reaches for by reflex.**
392
- Every other verb in a trace is `VERB :: tail`. A line that is faithful about
393
- the numbers and off by two characters in its punctuation must still parse.
394
- Tolerance is a net under the contract, not a licence to reshape the line.
395
- - **A saved dispatch return backfills a run made before any of this existed.**
396
- `{run_dir}/<slug>/*.json` is read as a THIRD source when and only when — it
397
- carries `dispatched: true` and a `trace_line` this parser accepts. That is the
398
- CLI's own payload read back, not a narrative about it, which is what separates
399
- a recovery from an invention. It carries no date and **none is derived from an
400
- mtime** (the `/orc-pact` UNCHECKABLE rule), so `--since` excludes those rows and
401
- says how many.
402
- - **Every count says which source it came from,** on both surfaces. "ORC wrote
403
- this down itself" and "a trace happened to mention it" are different levels of
404
- confidence in the same total. Two ABSENT counts are named rather than absorbed:
405
- a torn log line, and an undated saved return a date filter dropped — a report
406
- that is quietly short by three rows is the exact failure being fixed.
407
-
408
- **And the panel now survives its own upgrade.**
409
-
410
- `orc upgrade` replaces the package the running `orc ui` server was loaded from.
411
- Node read `bin/webui` at require time and `STATIC` is a one-time walk at boot, so
412
- an upgraded panel keeps serving the old bytes: the version in the rail does not
413
- move, a new panel does not appear, and a fixed bug is still there. The remedy was
414
- three manual steps nobody was told about stop the server, re-run `orc ui`, open
415
- the new URL.
416
-
417
- - **The server hands itself over.** After a maintenance action DECLARED as
418
- replacing the install (`update`, `prune`, `fix`, `upgrade`never
419
- `update-global`, which targets `~/.claude`) succeeds, the panel restarts on the
420
- **same port and the same token** and the open tab reloads itself. A successor on
421
- a new address is not a restart; it is a second server, and the tab you are
422
- looking at would still point at the corpse.
423
- - **CLIENT-TRIGGERED, never automatic on the job's close handler.** The job's
424
- output lives in the server's memory, so restarting the instant a command
425
- finished would destroy the record of what it did before anyone read it. It also
426
- means a tab that is already closed leaves the old process running, which is the
427
- safe resting state.
428
- - **The token travels in the ENVIRONMENT, never in argv** — it authenticates a
429
- write surface, which puts it in the same class as the credentials `orc extra`
430
- refuses on a command line. It is read once at boot and deleted from
431
- `process.env`, so no CLI subprocess the server shells out to inherits it.
432
- - **A failed handover is a note and two commands, never a broken page.** The old
433
- panel keeps working; it just prints `orc ui --stop` and `orc ui`. And the
434
- confirmation says the restart is coming BEFORE the apply — a panel that reloads
435
- itself with no warning reads as a crash.
436
-
437
- ---
438
-
439
- ### v0.53.1 — "up to date" now names what it checked _(2026-08-23)_
440
-
441
- **A one-line diagnostic for the update check that could not be questioned.**
442
-
443
- The update check was never broken, and that was the problem. `orc version` reads
444
- `package.json` from `UPDATE_URL`; `orc upgrade` installs from `TARBALL_SPEC`.
445
- They are two different URLs on what is *normally* the same branch — and only the
446
- second one was ever printed, on either surface. The Maintenance panel's `source`
447
- row shows the install tarball, so a reader concludes the version comparison read
448
- main too.
449
-
450
- That gap makes a true statement unfalsifiable. A maintainer who cut v0.53.0 on an
451
- unmerged release branch saw `✓ up to date` against a main that was still at
452
- 0.52.0, with nothing on screen to distinguish "you are current" from "the release
453
- never reached the ref this reads". There is no way to tell those apart from the
454
- output, which is why it reads as a defect in the checker.
455
-
456
- So the number and the ref it came from now travel together, everywhere the number
457
- is reported:
458
-
459
- - **`orc version`** prints `✓ up to date (azure-id/orc@main is at 0.52.0)`, and
460
- the offline branch names the unreachable ref rather than saying "source".
461
- - **`orc version --json`** gains `checked_source` (the URL) and `checked_ref` (the
462
- `owner/repo@ref` label). This is not a new idea: `orc changelog --json` has
463
- always carried its own `source`, and this is that field's missing twin — a
464
- field the human path implied and the JSON omitted.
465
- - **`orc ui` Maintenance** gains a `version read from` row beside `source`, so
466
- the two URLs are visibly two URLs. The fixture carries both fields.
467
-
468
- `checkSourceLabel()` shortens a `raw.githubusercontent.com` URL to
469
- `owner/repo@ref` and returns anything else verbatim a custom `ORC_VERSION_URL`
470
- is shown as written rather than mangled into a label that does not describe it.
471
-
472
- **Nothing about the check itself changed.** No new request, no new cache, no
473
- change to the 24h TTL, `ORC_NO_UPDATE_CHECK` or the comparison. The only thing
474
- that is new is that the answer can now be checked.
475
-
476
- ### v0.53.0the schema the provider rejected, and a routing table you can read _(2026-08-23)_
477
-
478
- **One outage, one defect visible at a glance, and the Extra panel rebuilt.**
479
-
480
- **The outage.** Engine `cli` on **codex** had been 100% dead for a release, and
481
- the suite was green the whole time. ORC handed codex an `--output-schema` with
482
- `additionalProperties: true`; OpenAI structured outputs require a **closed**
483
- object at every level, so every dispatch was an **HTTP 400 raised before the
484
- model was ever reached** fast, free, and reported as something vague. Flipping
485
- only that flag is a **second** 400, this time naming `files_changed`, because
486
- `required` must list every key in `properties`. An optional field is a nullable
487
- union now, never an omission from `required`, and the shape is documented as
488
- **provider-dictated rather than chosen** the comment calling it "deliberately
489
- minimal" is what produced the bug.
490
-
491
- Three things went with it:
492
-
493
- - **The classifier was reading the wrong stream.** codex relays the upstream
494
- `invalid_request_error` inside its own event stream on stdout while printing a
495
- benign notice on stderr, so a precisely-diagnosable, non-retryable failure came
496
- back as `unknown` and `retry: false` was reached by luck. The codex adapter
497
- now classifies from **the provider's own error object** first, and
498
- `classified_from` says which of the two answered — a field that reports where
499
- a verdict came from must not lie about it.
500
- - **A measurement was being reported as unknown.** codex *does* report
501
- `cache_write_input_tokens`; the adapter declared three usage kinds, so ORC
502
- threw a real number away and then said it was never measured.
503
- `reasoning_output_tokens` is still deliberately unread — the Responses API
504
- counts it inside `output_tokens`, and an unproven pricing change is worse than
505
- a missing one.
506
- - **And the reason it shipped green: the fake was more permissive than the
507
- provider.** It asserted the schema existed and mentioned `status`, and modelled
508
- none of OpenAI's rules. That is the **third release in a row** broken by the
509
- same shape — `--auto` renamed, a greedy `-f` array, now an open schema. **A
510
- strict third-party parser fails for free, and it looks like a model problem.**
511
- The defence is the same every time: the fake must be at least as strict as the
512
- real thing. It now rejects both 400s by name.
513
-
514
- **The ellipse.** A ready-and-verified tool card drew its "connected as" chip as a
515
- 250px green ellipse. `.ex-tool` declared `grid-template-rows: auto auto auto 1fr
516
- auto` — but **four states carry four different numbers of children**, so the chip
517
- landed in the `1fr` slack row, stretched (a grid item's default), and a 999px
518
- radius did the rest. It hit whichever ready card had the shortest content in its
519
- row, so it was never about one tool. The card is a flex column now, with no row
520
- template at all. The old test asserted the property was *present* — which it was,
521
- while the panel drew an ellipse.
522
-
523
- **The Extra panel.** It was nine cards in one 8,786px scroll: no first step, no
524
- last step, no way to be *done* with a section.
525
-
526
- - **Five tabs** on the panel's own precedent Setup, Routing, Limits, Spending,
527
- Providers. The header strip and "what needs your attention" stay outside them,
528
- because a caution you have to go looking for is a caution nobody reads. The
529
- open tab survives a re-render, and the gate still decides what **exists**: with
530
- nothing connected, three tabs are not rendered as empty shells.
531
- - **One vertical band ladder** replaces the horizontal rail *and* the duplicate
532
- list of rows below it. The target is no longer truncated, the widths no longer
533
- lie (a `min-width` floor was fighting the percentage), nothing is off-screen,
534
- there is a **legend** green means the work leaves your machine — and the row
535
- you read is the row you edit.
536
- - **The plain-language range is the CLI's.** `orc extra route` gains `range`
537
- ("scores 0 to 29") and `meaning` per row, printed on the human path as well.
538
- Writing "simple work" beside a score in the panel would be the panel deciding
539
- what a score means.
540
- - **One sentence and one control per tool state**, with the diagnostics behind a
541
- disclosure.
542
- - **Wording**: the panel was serving **design rationale as user instruction**.
543
- Six keys split the instruction first, in Simplified Technical English, the
544
- reasoning collapsed underneath. Nothing deleted, both languages, and the
545
- rationale keeps its voice.
546
-
547
- Setup per provider: **[`guides/extra-models.md`](guides/extra-models.md)**.
548
-
549
- ---
550
-
551
- ### v0.52.0 the connection that could not be used, and the routing nobody could see _(2026-08-23)_
552
-
553
- **Eleven defects, one release.** Five came out of a real `/orc-fast` run against
554
- a verified, routed local tool a run that fell back to Claude twice over, for
555
- two unrelated reasons, neither of which was the model. Six more came out of
556
- reading the panel afterwards, and they are one theme with several faces:
557
- **Extra was invisible to every surface that is not the Extra panel.**
558
-
559
- **The two that killed that run.**
560
-
561
- - **`opencode` dispatch was dead on arrival.** `-f` is a yargs **array** flag,
562
- and a yargs array is **greedy**: every non-flag token after it is swallowed as
563
- another file path. ORC pushed the message last, so `message..` arrived empty
564
- and opencode exited 1 in its own parser `dur=0m01s`, `tok=none`,
565
- `outcome=failed`, looking exactly like a model problem. Engine `cli` on that
566
- tool was 100% dead for a release. The message comes first now, `-f` comes
567
- last where it has nothing left to eat, and the test fixture asserts **that a
568
- message arrived** rather than that a flag was present.
569
- - **A tool that signs itself in was being forced into the vault.** `--tool-auth`
570
- has existed in the CLI since v0.51.0 and the panel offered two radios, so a
571
- connection that needed **no key from ORC at all** got a vault, and the vault
572
- then locked the run. There is a third credential source in the form now,
573
- offered only where it can be true, and pre-selected when the card you pressed
574
- Connect on says the tool is already signed in.
575
-
576
- **The passphrase finally has a lifecycle, and a deadline.** A vaulted key needed
577
- `ORC_EXTRA_KEY` in the environment or nothing, so a green, verified, routed
578
- connection answered `locked` at wave 1 and the run announced a Claude fallback.
579
-
580
- - `orc extra session <name> --save --ttl <days>` saves it, **on stdin**
581
- `--passphrase <value>` is refused by name, like every other secret here. The
582
- deadlines are a closed set (1 · 3 · 7 · 14 · 30 · 90 · 180 · 360): no `0`, no
583
- "forever", and **no auto-extend on use** a deadline that renews itself is
584
- not a deadline.
585
- - The cache lives **in the project**, gitignored beside the vault, and is
586
- encrypted under the pepper that lives in your home directory. **A copy of the
587
- project folder opens nothing.** That is the one genuine property this file
588
- has, and it is said out loud wherever the countdown appears along with the
589
- honest half: while it is saved, anything running as you on this computer can
590
- open the connection.
591
- - **`orc extra preflight` is a P0 gate before wave 1.** Active is fine; expiring
592
- is fine and names the date; **expired or missing STOPS the run**. It never
593
- falls back`extra_on_failure` is about an endpoint that failed, and a
594
- deadline you set 30 days ago deserves a stop, not a substitution. The
595
- credential is deleted and the connection stamped expired; **the routing rows
596
- survive**, because the bands are work you did.
597
- - The save modal at connect time **has no exit but Save**, and one destructive
598
- escape that is named rather than a Cancel.
599
-
600
- **Extra is visible outside its own panel now.**
601
-
602
- - **`orc extra lanes`** answers the question a band cannot: *which lane does this
603
- govern?* `/orc` scores every task; `/orc-fast` pins one executor and resolves
604
- its band **at both edges**, requiring them to agree. That rule was implemented
605
- and written down and rendered nowhere. The lane table is code now, mirrored
606
- against the markdown in both directions by a golden test.
607
- - **The Flow score table sees Extra.** With `extra: on` it renders the composite
608
- instead of the Claude ladder a band that cannot route **keeps its row** and
609
- names its fall-through, and `extra: off` renders byte-identically to before.
610
- - **`fixed_executor` can name a foreign target** (`extra:<profile>/<provider>/<model>`),
611
- offered only for verified connections. The session-tier rule is skipped for it
612
- — it is not a Claude model — and **the compiled flow says so**, because a rule
613
- silently disabled is worse than no rule.
614
- - **`/orc-doc` has its own switch.** `orc doc extra <slug> --set
615
- off|writer|checker|both`, stored per document, default off. A global setting
616
- turning Extra on for a throwaway runbook also turned it on for the PRD you
617
- ship, and a document's voice is the deliverable. `orc doc next` names the
618
- sections going off Claude **before** the wave.
619
-
620
- **Three panel defects, and one of them was in every modal.**
621
-
622
- - A **connected** tool no longer offers Connect. `connected` and `verified` are
623
- computed by the CLI, never joined in the panel, and the verified card **has no
624
- Connect button at all** rather than a disabled one.
625
- - **Scrolling inside a modal scrolled the page behind it** — every modal in the
626
- app, not just Extra's. Fixed with scroll containment and a body lock.
627
- - **Two tool cards no longer sit at different heights.** A card declares its rows
628
- now, so the button in one lines up with the button in the other.
629
-
630
- **Wording.** The Extra panel's instruction text labels, hints, errors, gates,
631
- countdowns, the passphrase modal end to end — is Simplified Technical English,
632
- with a one-page term list at `bin/webui/i18n/TERMS.md` and a test for the cheap
633
- half. Rationale prose keeps its voice and only gets shorter: flattening *"it
634
- stops someone at your keyboard, not someone who copied the file"* makes it true
635
- and useless. One rule is not negotiable and now has a test: **never simplify a
636
- CLI-computed value** a simplified state word is a state that does not exist.
637
-
638
- New: `orc extra session`, `orc extra preflight`, `orc extra lanes`, `orc doc
639
- extra`, `orc extra dispatch --passphrase-stdin`, and one config key
640
- (`extra_passphrase_ttl_days`, default 30). `orc extra keyhelp` now carries the
641
- per-OS command for setting an environment variable with a placeholder, never a
642
- key, and ORC still refuses to run `setx` or write to your shell profile itself.
643
-
644
- ---
645
-
646
- ### v0.51.0 — the tools you already have, and a connection that proves itself _(2026-08-22)_
647
-
648
- **`orc extra` connections.** Two of the things ORC can hand work to are not
649
- websites they are **programs on your own machine**, and the last release could
650
- only reach them by hand-typing a binary name into a `custom` profile. They are
651
- first-class providers now, with a connect box each, a model dropdown built from
652
- what **your** account can actually reach, and a connection test that proves
653
- something answered rather than proving a file exists.
654
-
655
- - **A program can simply not be installed, and the panel says that FIRST.** Four
656
- states, computed fresh every time and never remembered: `absent`,
657
- `outdated`, `unauthenticated`, `ready`. An absent tool gets no Connect
658
- button, no Test button and no model list every one of those is a button that
659
- cannot succeed. `orc extra add` refuses too, and names the install command
660
- instead of leaving you a profile that will never work.
661
- - **ORC opens your own terminal and runs the install there.** Not a hidden
662
- background job inside one, an administrator prompt, a permissions error, an
663
- 80 MB download and a forty-second wait all look identical: *nothing happened*.
664
- The exact command is on screen before the button, the window is yours to read
665
- and Ctrl-C, **ORC never asks for administrator rights**, and if no terminal can
666
- be opened you get the command to paste rather than a dead button.
667
- - **One tool has an install-free route and one does not**, and `null` means
668
- *there is none* rather than *ORC did not look*. The two never render the same.
669
- - **The connection test is a ladder now, and every rung reads as itself.** Is the
670
- program there · is it new enough · does it have a sign-in · which models can
671
- this account reach · and only when you ask **does a real message actually
672
- come back**, with the round trip, the reply, and the four token counts kept
673
- separate. Free rungs always run; the paid one is its own button, and what it
674
- costs is quoted before you press it.
675
- - **A model that is LISTED is not a model that WORKS.** A live list is what the
676
- provider offers; an id in it can be dead upstream. `orc extra models <name>
677
- --test <id>` is the only thing that tells those two apart, and the caveat rides
678
- beside every dropdown.
679
- - **Neither local tool says which model answered**, so a quiet substitution is
680
- invisible on that engine. ORC prints that sentence rather than an empty field —
681
- and one of the two reports three token kinds, not four, so the missing one
682
- reads as an em dash and never as a zero.
683
- - **A models list anyone can read is not proof of your key.** A provider that
684
- serves its catalogue without a credential would otherwise mark a connection
685
- verified with a typo'd key. That answer is now recorded for what it was and the
686
- test carries on to something that actually needs the key.
687
- - **`extra_enabled` cannot be switched on before anything has answered.** It
688
- would have armed nothingevery task would fall straight back to Claude, so
689
- the switch read ON and meant OFF. The refusal names what to do next, and the
690
- Extra panel shows only the connect surfaces until then: no routing table, no
691
- limits, no cost report.
692
- - **A fix, not a feature:** every dispatch to one of the two local tools was
693
- failing, and failing in a way that looked like a bad model id. One of them
694
- renamed a permission flag and refuses unknown ones outright. ORC picks the flag
695
- from the version it probed, and a tool that answers with its own help text is
696
- now reported as a flag problem by name.
697
- - **ORC never writes another tool's credential store.** Your key stays in ORC's
698
- vault or in your own environment variable and is handed to the program for each
699
- run so nothing global changes, revoking it in ORC actually revokes it, and if
700
- you already signed that tool in yourself, ORC leaves it alone.
701
-
702
- ---
703
-
704
- ### v0.50.0 — work that runs somewhere else _(2026-08-22)_
705
-
706
- **`orc extra`** — a band of ORC's score ladder can now be answered by a
707
- **non-Claude worker**: DeepSeek, Z.ai (GLM), Moonshot (Kimi), MiniMax, Qwen,
708
- Xiaomi MiMo, StepFun, SiliconFlow, OpenRouter, a local Ollama, any
709
- OpenAI-/Anthropic-compatible endpoint you name, or an agentic CLI you already
710
- have (`opencode`, `codex`). ORC's own session never moves this routes
711
- **workers**, not the conductor.
712
-
713
- - **Off by default, and a connection that has never answered can never be used.**
714
- `orc extra ping` is the gate, it climbs the cheapest rung first (a free model
715
- list; only then a one-token completion), and it records WHICH rung answered
716
- "verified by a models list" and "verified by a real completion" are different
717
- guarantees and one green tick for both would be a lie.
718
- - **Every armed run says so BEFORE the work starts.** An `extra:` line joins the
719
- Phase-1 preflight naming how many tasks will cross the boundary and where they
720
- go. It has no quiet version. The failure this whole subsystem is shaped around
721
- is not a wrong answer it is work leaving your machine without anybody saying
722
- so.
723
- - **A gap in the routing table is not a hole it is Claude**, and it is printed
724
- with the exact agent it resolves to, so "I left the top band on Opus on
725
- purpose" and "there is no top band" can never look the same. Overlapping rows
726
- are refused by name.
727
- - **Risky work stays.** A task whose plan cites `risk[]` (money, auth, security,
728
- migration, concurrency, data-integrity) never leaves Claude, and neither does
729
- anything in an area a boundary card marks REFUSE — in `warn` mode as well as
730
- `block`.
731
- - **Three engines, and only one composes the request body.** `api` is therefore
732
- the only one that can enforce the declared-files fence or carry a privacy
733
- policy, so a return claiming the fence held on the other two is rendered as a
734
- WARNING: a constraint that was never applied is never reported as kept.
735
- - **Your key never reaches a command line.** `--key <value>` is refused by name.
736
- Use an environment variable (recommended) or the encrypted vault
737
- AES-256-GCM under a passphrase ORC does not store and cannot recover, stored
738
- only after a green test, with a countdown that prints every time and a
739
- self-destruct at ten wrong attempts that keeps the profile. New in this
740
- release: `orc extra ping --passphrase-stdin` re-tests a key that is already
741
- stored.
742
- - **No shipped model ids and no shipped prices.** Both go stale within a quarter
743
- and both get believed. `orc extra ping` reads the live model list from the
744
- provider; `orc extra rates` prints the JSON to paste for a price. Until a pair
745
- has a rate, `usd` reads as an em dash a cost ORC did not price itself is
746
- never printed.
747
- - **`orc extra stats`** joins ORC's own traces per profile per band and reports
748
- four token kinds separately, plus the three things only it can see: a
749
- SUBSTITUTION (you did not get the model you asked for), a REROUTE (you got the
750
- model and a different company served it) and a FALLBACK (it did not work and
751
- Claude finished the job).
752
- - **A failed foreign dispatch is never a dead run.** It falls back to the Claude
753
- band that task would have had, announced. `extra_on_failure: stop` is there for
754
- people who would rather stop than quietly start paying full rates.
755
- - **New panel: `orc ui` ▸ Extra.** The boundary paragraph renders always, never
756
- behind a click. One 0→100 rail, green where your connection runs the work and
757
- blue where Claude does, with every unrouted range keeping its slot. Staging a
758
- change previews it before anything is written. The panel names no provider, no
759
- model and no agent it draws what the CLI computed.
760
- - **The `orc ui` boundary is NARROWED, not broken.** The panel still never runs a
761
- lane and never does agentic model work; the one model-shaped thing it can
762
- trigger is a connectivity probe, and even that runs through the CLI in a
763
- subprocess like every other action. A probe is a diagnostic, the family
764
- `orc doctor` is in.
765
- - **Nine config keys**, one canonical contract
766
- (`_shared/extra-dispatch.md`), a new `EXTRA` trace verb, `orc extra doctor`
767
- with eleven findings, and a stance stated in exactly one place for every other
768
- lane — including `/orc-challenge`, which never routes foreign, because swapping
769
- a lens for a different model does not make the lane cheaper, it changes what is
770
- being measured.
771
- - **Also:** the test suite pins `--test-concurrency=8`. At one worker per core,
772
- the files that spawn real child processes and the one that derives scrypt at
773
- N=2^17 starved each other and produced failures that looked exactly like
774
- regressions. Determinism is worth 11% of the wall clock.
775
-
776
- Setup detail per provider: **[`guides/extra-models.md`](guides/extra-models.md)**.
777
- A full walkthrough: `orc mock-run orc-extra`.
778
-
779
- ---
780
-
781
- ### v0.49.5 house rules are text, and the hand-back writes itself _(2026-08-21)_
782
-
783
- Two fixes to `/orc-doc`, both the same shape: stop making a person work around
784
- the tool.
785
-
786
- - **House rules are a PLAIN TEXT config now, not a form.** The first cut modelled
787
- a rule as a row one line, one id, a P0/P1/P2 dropdown, an enable flag, added
788
- one at a time. Nobody's real P0 fits on one line, and filing it as four
789
- separate rows to keep the CLI's argv simple was the tool asking the user to
790
- work around it. The ledger is now `.claude/orc/doc-house-rules.md`: three
791
- headings, and **as much text under each one as you want**, handed to every
792
- writer verbatim. Open it in your editor, or edit it in **one box** in
793
- `orc ui` **Docs** no dropdown, no Add button, no per-rule row.
794
- - **New: `orc doc rules set|add|clear --priority P0 --text "…"`** (multi-line is
795
- the point), plus `set-all` for the whole file and `--set-file` for a bulk
796
- replace. `remove`, `enable`, `disable` and `move` are **refused by name** a
797
- command that used to work and now does nothing is worse than one that says
798
- what replaced it.
799
- - **Migration is lazy, free and non-destructive.** The old `doc-house-rules.json`
800
- is read once, converted, and **left exactly where it was**. A rule you had
801
- DISABLED is never resurrected — it is left behind and counted in the output.
802
- - **`RESUME.md` is written by the CLI, on every state change.** It used to be
803
- prose the orchestrator was told to write at every stop, which is the bet this
804
- repo has already lost twice: the hand-back you are TOLD to write is the one
805
- that goes missing on the run a usage limit killed. `doc.json` has exactly one
806
- writer, so the hand-back hangs off that it exists from `orc doc init` onward
807
- and is never behind the disk. `orc doc resume-file <slug>` writes it on demand.
808
- - **Every question `/orc-doc` asks you now ends by pointing at it** (hard rule
809
- 16): the file path, and the one line to paste into a brand-new session. The
810
- page itself is written for someone who does not read code — what the document
811
- is, where the files are, what is not written yet, and what happens next.
812
-
813
- ---
814
-
815
- ### v0.49.4 the panel was being handed half an answer _(2026-08-20)_
816
-
817
- One bug, and it could hit any `--json` read big enough.
818
-
819
- - **Fixed: a large `--json` payload was truncated whenever something read it
820
- through a pipe.** `emitJson` wrote to stdout and then called `process.exit()`.
821
- On macOS and Linux a pipe write is asynchronous, so the exit threw away
822
- whatever had not flushed and `orc ui` reads every panel through a pipe. On a
823
- 1,100-file repo `orc wiki coverage --json` computed a perfect 30 KB object, the
824
- server received the first 9 KB, `JSON.parse` failed, and **Knowledge
825
- Coverage** reported that the repo had neither a registered wiki nor a git
826
- repository on a wiki that was FRESH and 39% covered. `orc wiki docs` was hit
827
- the same way; `wiki status` escaped only because it prints and returns instead
828
- of exiting. Windows pipes are synchronous, which is why it never showed up in
829
- development. Every `--json` read now writes through fd 1 synchronously.
830
- - **The Knowledge panel no longer reports a broken read as an empty repo.** A
831
- failed request renders the CLI's own reason and output, the way every other
832
- panel has since v0.49.2 — the generic "it needs a registered wiki and a git
833
- repository" line is for a repo that actually has neither.
834
- - **Also: git output is no longer capped at Node's 1 MB default** (v0.49.3),
835
- which would have truncated `git ls-files` on a repo of roughly 25,000 files.
836
-
837
- ---
838
-
839
- ### v0.49.3 coverage on a large repo _(2026-08-19)_
840
-
841
- One fix, and the bigger the repo the more it mattered.
842
-
843
- - **Fixed: `orc wiki coverage` reported "not a git repository" on a large,
844
- freshly refreshed wiki.** Every git call ORC makes ran through `spawnSync` on
845
- Node's **1 MB** default output buffer. `git ls-files` in a big repo prints more
846
- than that, the child is killed with `ENOBUFS`, and the exit status comes back
847
- `null` which the code read as *there is no git here*. So `orc ui`
848
- **Knowledge** **Coverage** showed no numbers at all on the repos where the
849
- number matters most, and `orc wiki impact` was one wide diff away from the same
850
- failure. The buffer is now **256 MB**, and a spawn error is read as an error
851
- instead of being inferred from the status code.
852
-
853
- ---
854
-
855
- ### v0.49.2 — house rules, a run map before you pay, and three defects _(2026-08-18)_
856
-
857
- Quality of life on `/orc-doc`, plus three bugs — one of which was breaking a
858
- panel outright. **Zero new agents, zero new skills.** Everything here obeys the
859
- standing rule: **the CLI computes, the panel and the skill render.**
860
-
861
- #### `/orc-doc` house rules
862
-
863
- A **house rule** is your project's own standing instruction about **what a
864
- document says and how it reads**: *"open with a one-paragraph summary a PM can
865
- read on a phone"*, *"money always carries its currency"*, *"use the customer's
866
- words, not the internal table name"*. Before this, the shipped rules were the
867
- only rules.
868
-
869
- - Three priorities. **P0** must, and it beats every ORC style preference; **P1**
870
- should, and breaking it is recorded as a gap; **P2** prefer.
871
- - Stored **verbatim** in `.claude/orc/doc-house-rules.json` one writer,
872
- `orc doc rules`, outside `templates/` so `orc update` never touches it. A rule
873
- is one line; a multi-line one is refused by name with the hint to add two.
874
- - **Each document freezes the set it started with.** If a P0 changes at wave 3,
875
- half the document silently no longer complies and nothing on disk says so so
876
- `orc doc rules <slug>` reports frozen-vs-project and **names every rule that
877
- was added, changed or removed**, never a "rules changed" boolean.
878
- `--sync` re-freezes deliberately and **lists the sections that predate the
879
- change**. It re-writes nothing: that would be ORC spending your money applying
880
- a rule change retroactively without being asked.
881
- - **Read FIRST in every dispatched slice**, above ORC's own rules that order is
882
- the contract.
883
- - **The boundary is declared, not detected.** House rules govern content and
884
- style; they can never change how the lane RUNS. The CLI cannot parse intent, so
885
- it does not pretend to: it prints the boundary everywhere it matters, and a
886
- rule that asks for a structural break comes back as `unsupported_request`.
887
- - New: `orc doc rules [add|remove|enable|disable|move|--sync|--set-file|--reset]`,
888
- a **House rules** card at the top of `orc ui ▸ Docs` (staged and batched, like
889
- every other write in the panel), and a `house-rules-drifted` audit finding.
890
-
891
- #### `/orc-doc` four rules ORC applies to every document, all free
892
-
893
- All four are deterministic lint rules, which is what makes them worth having:
894
- **no model is ever paid to notice a `TODO`.** Every one is narrow on purpose — a
895
- broad rule that argues with the author gets switched off.
896
-
897
- - **No questions or confirmations in the body.** The deliverable answers; it does
898
- not ask. `TBD`, `TODO`, `TBA`, *"to be confirmed"*, and a line that is only a
899
- question put to you as an approver. **Two exemptions:** fenced code, and a
900
- section your own outline calls *open questions / risks / assumptions*.
901
- - **Missing information is `N/A` plus one short line, never filler.** A warning,
902
- never an error you may have a reason.
903
- - **A section well over its planned length is a finding** (1.5× its budget), plus
904
- per-section line and word counts in `orc doc lint --json`. Signals, not gates.
905
- - **No local-only references.** No `src/foo.ts:42`, no absolute path, no
906
- `./relative`, no `localhost`, no `file://`, no link to a local `.md` the
907
- person reading a PRD has no repository. Fenced code is always exempt, because a
908
- code example that *shows* a path is content. New config `doc_local_refs`
909
- (`off|warn|error`, default `error`): a genuinely internal runbook legitimately
910
- names local paths, and a lint rule with no switch gets fought instead of used.
911
-
912
- #### `/orc-doc` a supplied template is a cage, not a suggestion
913
-
914
- `--template` set the outline and then nothing stopped a writer adding a heading
915
- it never had. It now locks by default: the slice carries the allowed headings,
916
- `orc doc lint` errors on a stray one, **`orc doc parts --confirm` refuses the
917
- part that grew one and writes nothing**, and `orc doc audit` reports both
918
- `template-drift` and `template-moved` (your template file itself changed —
919
- reported, never auto-synced). `--template-soft` opts out; a shipped base template
920
- stays a floor.
921
-
922
- #### `/orc-doc` what it will cost, and what it did cost
923
-
924
- - **`orc doc forecast <slug>` — the run map, once, before the first paid wave.**
925
- How many sections, how many waves, how many agents per wave, **how many times
926
- it will stop**, and a token range with its sample count. Computed from the same
927
- batcher the dispatch uses, so it can never describe a run that will not happen.
928
- Every honesty rule of `/orc-budget` is inherited: four token kinds never
929
- blended, no dollars without a dated price table, no quota without a known plan
930
- and **with no history it refuses rather than invent**, offering the
931
- `--naive` price-table floor instead. `orc doc next` names it exactly once; a
932
- changed outline or write mode invalidates it.
933
- - **`orc doc cost <slug>` — joined across every session the document spanned.**
934
- `orc budget actual` works per run, and a document is not a run. Per role and
935
- per section, from ORC's traces joined to your local usage transcripts. A slice
936
- that covered two sections splits evenly, said out loud; **a section nothing can
937
- be joined to reads `—`, never `0`.** `unattributed` is always printed.
938
- - Both render in `orc ui ▸ Docs` with a stacked four-kind token bar, so
939
- cache-read stays visibly separate from the rest.
940
-
941
- #### `/orc-doc`an edit round tells you where to look
942
-
943
- `orc doc lint <slug> --section <id>` lints one **section file** and returns
944
- **part-local** line numbers, and every finding on an edit-round slice carries its
945
- file and line. The skill prints one line per finding
946
- (`sections/03-scope.md · line 42 · long-sentence`) and, after the round, each
947
- file it touched. The compiled `document.md` line number is deliberately never
948
- carried: it is stale the moment anything is written.
949
-
950
- #### Fixed the Overview card printed over itself
951
-
952
- `.run-card` is a four-column grid (caret · chip · mid · age) and the Overview
953
- built a card with **three children and no caret**, so the chip landed in the 16px
954
- caret column and printed straight over an 88px slug, which wrapped one word per
955
- line. A grid never complains. Every variant now declares its own column count
956
- `.no-caret` for a row that navigates, `.has-extra` for an optional second chip
957
- and the same collision in the Docs list (from its "you edited it" chip) is fixed
958
- the same way. The age column now carries the age `run list --json` always knew.
959
-
960
- #### Fixeda run could never be marked done
961
-
962
- `RESUME.md` existing IS the "unfinished" flag, and ORC deletes it at `FINISH`. So
963
- a run you abandoned was waiting **forever**: `orc resume` kept offering it, the
964
- Overview kept counting it, and the upgrade preview kept refusing with "N run(s)
965
- are still waiting" with no way out short of deleting a file by hand.
966
-
967
- `orc run close <slug> --reason "<why>"` **moves** `RESUME.md` to
968
- `RESUME.closed.md` and records why. **It deletes nothing**, and `orc run reopen`
969
- puts it back byte for byte. The new state is **`closed`**, deliberately not
970
- `done`: the disk cannot prove a run finished, only that you said you were
971
- finished with it. A reason is required a state change nobody wrote a reason for
972
- is a state nobody can audit. Everything else follows from one boolean: `resume`
973
- skips it, `run list` keeps the row *and* its reason, and the upgrade unblocks.
974
- Buttons for both in `orc ui Runs`, and inline on the Overview card that was
975
- complaining.
976
-
977
- #### Fixed one corrupt challenge ledger 500'd the whole panel
978
-
979
- Two crash classes: a ledger truncated by a killed session, and a ledger with no
980
- `goals` key. Both threw a Node stack with nothing parseable on stdout, so
981
- `orc ui Challenge` showed a bare 500 and **every healthy cycle disappeared
982
- with the broken one**, which is the opposite of what a listing is for.
983
-
984
- - A broken cycle is now a **row** that reads `UNREADABLE` and carries the parse
985
- error. It is a list-level state: it never reaches the pass gate and never
986
- claims a verdict.
987
- - **No `--json` read can emit a stack trace any more.** A throw comes back as
988
- `{ok: false, reason: "crashed", command, error, hint}` with its own exit code
989
- every `--json` route inherits it.
990
- - A 500 from the panel's API now carries the CLI's own reason, and the panel
991
- renders it. A 500 with no message is what you actually saw.
992
-
993
- ### v0.49.1the challenge council, and a `--json` that stops throwing things away _(2026-08-18)_
994
-
995
- One release, two workstreams, and **zero new skills**. They ship together because
996
- they are the same defect seen twice: **ORC computes far more than it shows.**
997
- `computeWikiFreshness` builds a per-doc table that `--json` threw away;
998
- `challenge record` computes per-dimension, per-severity, per-iteration detail
999
- that the panel rendered as one chip. Both halves are "stop discarding what you
1000
- already computed" and only one of them also adds new thinking.
1001
-
1002
- ---
1003
-
1004
- ## Part A the challenge council
1005
-
1006
- ### Five more ways of looking, and none of them is ORC's to choose
1007
-
1008
- `/orc-challenge` had one grounded opinion (the judge) and one blind one (the cold
1009
- reader), and both read the artifact the same way: *does this document do what a
1010
- document is supposed to do?* Five ways of looking were missing, and each one is
1011
- missed for a different reason:
1012
-
1013
- | Role | It asks | It fails when |
1014
- |---|---|---|
1015
- | **The Contrarian** | where is the fatal flaw? | it assumes the artifact is fine and stops looking |
1016
- | **The First Principles Thinker** | are we even solving the right problem? | it accepts the framing it was handed |
1017
- | **The Expansionist** | what is being undervalued here? | it only counts what is wrong |
1018
- | **The Outsider** | what does this assume I already know? | it is an expert and cannot un-know things |
1019
- | **The Executor** | what do you actually do on Monday morning? | it grades the theory and never the first step |
1020
-
1021
- > **A lens raises; only the judge resolves. ORC proposes the council; the user
1022
- > picks it.**
1023
-
1024
- **`a lane that picks its own council` has broken this contract** — registered as
1025
- the fourth member of the family with `a lane that answers its own interview
1026
- question`, `a lane that picks its own favourite` and `a lane that fixes what it
1027
- judged`. A council chosen by ORC is ORC deciding **which kinds of criticism the
1028
- user is allowed to hear**, which is a bigger decision than any single finding in
1029
- the run. So `orc challenge init --council` has **no default** and refuses by
1030
- name, exactly like `--goal` since v0.47.0:
1031
-
1032
- ```
1033
- --council is required and has no default. ORC SUGGESTS a roster (from the kind
1034
- and the goal); the user PICKS it. […] Suggested for --kind tsd:
1035
- reader,contrarian,executor.
1036
- (a lane that picks its own council has broken this contract)
1037
- ```
1038
-
1039
- `none` is a first-class answer and reproduces the v0.47.0 review exactly. The
1040
- cost is stated in **dispatches**, never in dollars `/orc-budget`'s rule: no
1041
- dollar figure without a dated price table.
1042
-
1043
- ### Two of them cannot produce a finding without lying
1044
-
1045
- This is the most important decision in the release.
1046
-
1047
- **The expansionist.** A finding must carry `serves` the goal element it
1048
- advances and `record` DROPS one without it. Its entire brief is *"what upside
1049
- is everyone missing?"*, which by construction is **not** in the stated goal.
1050
- Given a `serves` field it would either invent a goal element or be silently
1051
- dropped. So it returns an **opportunity**: no severity, never in `findings[]`,
1052
- never near the pass gate, always with a `first_step` and a route
1053
- (`brainstorm | pact | grill | none`). It is conserved `--take` or `--drop`,
1054
- both requiring a reason and **this lane never builds one**.
1055
-
1056
- **The first-principles thinker.** Its most valuable output is *"you are asking
1057
- the wrong question entirely"*, and in this lane the question is the **frozen
1058
- goal**. A finding is measured against the goal; a premise challenge disputes the
1059
- **yardstick**. Those cannot be the same object. It returns a **premise**, and
1060
- exactly two resolutions exist, both a human's: adopt it (`orc challenge goals
1061
- --set`, a `regoal` that bumps `goals.version`) or dismiss it with a mandatory
1062
- reason that stays in the report forever. **The judge never sees that report** —
1063
- handing a judge a document arguing the frozen goal is wrong would bend every
1064
- finding it produced afterwards.
1065
-
1066
- > The three finding lenses feed **the judge**. The two non-finding lenses feed
1067
- > **the user**. That sentence is the whole architecture.
1068
-
1069
- ### The gate that makes five extra reviewers safe
1070
-
1071
- The obvious failure of adding five reviewers is that the judge quietly ignores
1072
- four of them and the run looks identical while costing five times more.
1073
-
1074
- > **Every id the council raised must appear in the judge's return with exactly
1075
- > ONE disposition and a reason. `council_coverage_pct` must be 100.**
1076
-
1077
- That is conservation applied to **input** instead of to carry-forward, and the
1078
- CLI enforces it without reading a word of prose: the orchestrator writes a
1079
- machine JSON beside every council report, and **`orc challenge record` reads that
1080
- directory itself**. The judge cannot shrink the set by omission, because the set
1081
- was never the judge's to report.
1082
-
1083
- ```
1084
- malformed verdict council coverage is below 100% every id the council
1085
- raised needs exactly ONE disposition (adopted | merged | rejected |
1086
- out-of-goal). Missing: O-003
1087
- ```
1088
-
1089
- **An adopted finding keeps the raiser's id.** `C-004` stays `C-004` in the
1090
- verdict, in the report, in iteration 9 which is what lets the panel say *"the
1091
- contrarian raised four of the six blockers this iteration"*, and how a user finds
1092
- out within two rounds whether a lens is worth its money.
1093
-
1094
- **PASS is computed exactly as before.** An adopted council finding is an ordinary
1095
- finding from that moment on; `challengeBlocking()`, `challengeOpen()`,
1096
- `challengeCounts()` and `challengeStateOf()` are untouched. The pass gate learns
1097
- nothing about the council.
1098
-
1099
- ### A selected role is never silently absent
1100
-
1101
- Rule 6 (`NOT-CHECKED` is never silent), extended from dimensions to roles. A
1102
- roster lens returns either a report or an explicit `{ "lens": …, "ran": false,
1103
- "reason": … }`, and silence is rejected by name:
1104
-
1105
- ```
1106
- malformed verdict executor is on the roster but returned neither a report
1107
- nor an explicit { "lens": "executor", "ran": false, "reason": "…" }.
1108
- A selected role is never silently absent.
1109
- ```
1110
-
1111
- The trace carries it too, so `orc stats` and `/orc-retro` see a NOT-RUN lens and
1112
- not only the panel:
1113
-
1114
- ```
1115
- CHALLENGE iter=2 findings=P0:1/P1:3/P2:6 coverage=100% council=4/5 raised=C:6,O:3,E:2 adopted=9 verdict=FAIL
1116
- ```
1117
-
1118
- ### Effort is a measurement, not a cost choice
1119
-
1120
- `outsider` is `low` for the same reason the cold reader is: a harder-thinking
1121
- outsider reasons its way *around* an unexplained acronym and reports the document
1122
- is fine, which is exactly the gap the instrument exists to find. **Nothing may
1123
- ever upgrade it.** `contrarian` is `high` because at low effort it returns the
1124
- three surface complaints the free lint already caught for nothing.
1125
-
1126
- That is why there is **no model or effort config key**: a key that lets
1127
- `outsider: low` be tuned is a key that lets the instrument be broken.
1128
-
1129
- All seven lenses are `claude-opus-5`, so **`opus5_only` is a no-op for this lane —
1130
- it is unaffected, not exempt** — and the agent count moves 46 → 51 with no paired
1131
- variants.
1132
-
1133
- ### The reader / outsider seam
1134
-
1135
- These two are the closest pair in ORC and the one place this release could have
1136
- shipped a duplicate instrument. The distinction is structural:
1137
-
1138
- | | `reader` | `outsider` |
1139
- |---|---|---|
1140
- | Told the audience | **yes** | **no** |
1141
- | What it generates | 8–15 questions the artifact *promised* to answer | nothing it reacts to what is on the page |
1142
- | What it returns | a **scored** questionnaire (`8/12`) | an **unscored** ranked list of assumed knowledge |
1143
- | The measurement | *can this be answered from the page?* | *what does this page assume you already know?* |
1144
-
1145
- They are dispatched with no knowledge of each other. Where they agree, that is
1146
- recorded as `corroborated_by` — the strongest comprehension evidence the lane can
1147
- produce, and **never an automatic severity bump**.
1148
-
1149
- ### The roster is frozen, and `council: null` is a real state
1150
-
1151
- Ledger `version: 2`, additive: every v1 key keeps its name, meaning and position.
1152
- The roster is a per-cycle **frozen** decision changed only by a recorded
1153
- `recouncil` event, which bumps `council_version` exactly like `goals.version`
1154
- and the iteration rail draws a **third** version break for it, because comparing
1155
- an iteration judged by three lenses to one judged by six is not a comparison.
1156
-
1157
- **There is no `challenge_council` config key.** A global default roster would
1158
- silently answer the one question this release exists to ask. A cycle opened
1159
- before v0.49.1 reads back with `council: null` and `record` refuses the next
1160
- iteration by name until it is answered `orc challenge council <slug>` exits 1
1161
- for that state, because **UNSET is an answer, not an error**.
1162
-
1163
- ### New commands
1164
-
1165
- | Command | Does |
1166
- |---|---|
1167
- | `orc challenge roles [--kind k] [--json]` | the lens catalogue. Static — it works with no cycle at all |
1168
- | `orc challenge council <slug> [--json]` | the frozen roster + per-iteration participation (0 set · 1 unset · 3 unknown) |
1169
- | `orc challenge council <slug> --set <csv\|all\|none> --reason "…"` | a recorded `recouncil` |
1170
- | `orc challenge note <slug> --from <json>` | opportunities and premises ONLY it refuses a `findings[]` key by name |
1171
- | `orc challenge premise <slug> <id> --dismiss --reason "…"` | |
1172
- | `orc challenge opportunity <slug> <id> --take\|--drop --reason "…"` | |
1173
-
1174
- ### The panel
1175
-
1176
- It **derives nothing**: it does not name a lens, does not know which class
1177
- blocks, does not compute a disposition and does not decide the suggestion. A test
1178
- greps the panel for every lens display name, every disposition word and every
1179
- agent name and fails if it finds one.
1180
-
1181
- New: a **Council card** directly under the goal (a NOT-RUN row keeps its slot
1182
- with its reason; a NOT-SELECTED row is muted with the line that would add it; the
1183
- council executor's `monday_morning` list sits here, because it is the most
1184
- legible thing this lane produces for a non-engineer); a **premise card** that is
1185
- the loudest thing on the panel when one is open and sits *above* the findings; an
1186
- **opportunities card** with no severity colour anywhere in it; a lens chip and an
1187
- `also found by` chip on every finding; and a per-lens legend under the
1188
- convergence chart.
1189
-
1190
- There is deliberately **no route for `council --set`** changing the roster is a
1191
- decision with a recorded reason the *lane* takes in conversation.
1192
-
1193
- ### Deliberately absent
1194
-
1195
- - **An anonymised peer-review round.** It doubles the dispatch count, and the
1196
- judge's adoption pass already reconciles the lenses. The payoff — *"two
1197
- advisors independently hit the same thing"* is `corroborated_by[]` at zero
1198
- extra cost.
1199
- - **A chairman agent.** ORC already has one: the advisor groups findings by root
1200
- cause and orders the fix. Rule 5 still holds — no advisor on PASS.
1201
- - **A `challenge_council` key, any model or effort key, a `block` mode on a
1202
- council output, a loop cap, and auto-severity from corroboration.**
1203
-
1204
- ---
1205
-
1206
- ## Part B the knowledge deepening
1207
-
1208
- ### `--json is not a summary`
1209
-
1210
- > A read's `--json` is the WHOLE computed object, not a summary. **A field the
1211
- > human path prints and the JSON omits is drift — and it is drift no lint can
1212
- > see, because both halves live in one function.**
1213
-
1214
- `wikiStatus()` computes `computeWikiFreshness(...)` and the terminal branch
1215
- printed the per-doc FRESH/AGING/STALE counts, **the worst doc's filename** (the
1216
- thing actually pinning the tier), the top five stale docs with their own
1217
- distances, and the crosslink boundary state. The `--json` branch emitted five
1218
- scalars and `blind` **as a count**. The panel therefore *could not* be as
1219
- detailed as the terminal, no matter how it was written.
1220
-
1221
- `wiki status --json` now carries `counts`, `worst`, `per_doc[]`, `blind_spot` as
1222
- the **file list it always was**, `orientation`, `crosslink`, and `free_repairs`
1223
- reused verbatim from `wiki plan` a user must never be able to pay for what a
1224
- free step fixes. **Every legacy key keeps its name, position and meaning** (`orc
1225
- doctor`, the overview tile and `_shared/detecting-artifacts.md` all read them)
1226
- and the exit code stays 0 in every state.
1227
-
1228
- ### You can finally see what the wiki contains
1229
-
1230
- `orc wiki` had six subcommands and **not one of them listed the docs**. A user
1231
- could learn the wiki was STALE with 14 docs and 47 commits of drift, and could
1232
- not learn what any of those 14 docs was about.
1233
-
1234
- | Command | Returns | Exit |
1235
- |---|---|---|
1236
- | `orc wiki docs [--json]` | the doc table: tier, its OWN distance, covers, usage, tags, retire hint | 0 · 1 none · 3 unregistered |
1237
- | `orc wiki show <doc> [--body]` | one doc + its tags + the free repairs that apply to IT | 0 · 2 unreadable · 3 unknown |
1238
- | `orc wiki coverage [--json]` | % of tracked files covered by ≥1 doc, uncovered set by DIRECTORY | 0 full · 1 gaps |
1239
- | `orc pattern show <lang> [--body]` | headings, conventions vs invariants, flagged conflicts | 0 · 1 absent · 2 unknown key |
1240
- | `orc gotcha show <id>` | one entry, EVERY field | 0 · 3 unknown |
1241
- | `orc gotcha list --archived` | the archive | 0 · 1 none |
1242
- | `orc gotcha prune --dry-run` | exactly what eviction would archive, and why | 0 none · 1 would prune |
1243
-
1244
- **`orc wiki coverage` is a REPORT and never a gate.** No threshold, no config
1245
- key, nothing branches on it a repo that deliberately documents four subsystems
1246
- out of forty is not broken, and a coverage percentage that starts nagging becomes
1247
- a number people game. The uncovered set is collapsed to directories and ranked by
1248
- file count, because *"240 uncovered files, all in `vendor/`"* and *"12 uncovered
1249
- files, all in `src/payments/`"* are opposite situations.
1250
-
1251
- **`--body` is opt-in** on both `wiki show` and `pattern show`: prose is returned
1252
- only on an explicit request, exactly one artifact at a time, rendered as DOM and
1253
- never as HTML.
1254
-
1255
- **`orc pattern show` invents nothing.** The codifier may not write a parseable
1256
- header today; with none it returns `headered: false` plus the headings it could
1257
- parse, and says so in one line. It **never** derives a "codified at" from the
1258
- file's mtime — the `/orc-pact` UNCHECKABLE rule.
1259
-
1260
- ### Two doctor findings, and the restraint is the design
1261
-
1262
- | id | Warns when | Fix |
1263
- |---|---|---|
1264
- | `wiki-unregistered` | the wiki is unregistered, drifted or corrupt | `orc wiki sync` — free, instant, and until it is done nothing can read the wiki at all |
1265
- | `wiki-debt` | tier is **STALE** and `wiki plan` has pending rows | `/orc-wiki refresh --top 2` |
1266
-
1267
- **`wiki-debt` fires on STALE and never on AGING.** Aging is a normal state every
1268
- living repo passes through, and a doctor that warns about it is a doctor people
1269
- learn to ignore. Deliberately not added: `pattern-missing` — a project with no
1270
- cached pattern is not misconfigured, and warning about it would be ORC nagging
1271
- for a paid scan.
1272
-
1273
- Both route to the Knowledge panel: *a caution routes to the panel that can CLEAR
1274
- it*, and `orc wiki sync` is a button there.
1275
-
1276
- ### `orc ui Knowledge` five tabs
1277
-
1278
- ```
1279
- Knowledge [ Wiki ] [ Coverage ] [ Code patterns ] [ Memory ] [ Peers ]
1280
- ```
1281
-
1282
- A header strip renders above them all — tier · docs · covered % · blind ·
1283
- pending · patterns · repair notes and **a value the CLI could not compute
1284
- renders as an em dash, never as a guess.**
1285
-
1286
- - **Wiki** — the tier card with the **worst doc named** (a hash is not something
1287
- anybody can go and refresh), the per-doc counts as a stacked bar, free repairs
1288
- above everything priced, and **the doc table**. A row expands in place, one at
1289
- a time, detail fetched on first open.
1290
- - **Coverage** one honestly-qualified number, the uncovered set by directory,
1291
- the structural blind spot as the file list it always was, and one line that is
1292
- not optional chrome: coverage is a report, not a target.
1293
- - **Code patterns** — per language, with **the conflicts the codifier flagged in
1294
- their own block**: they are the most decision-shaped thing in the file and were
1295
- invisible outside it. Reveal shows the text that is injected literally into
1296
- every executor slice; a user who cannot read it cannot trust it.
1297
- - **Memory** every field the CLI already emitted, headroom against
1298
- `gotchas_max`, and a **preview-then-apply prune that names every entry** (a
1299
- count is not consent). The archive is reachable and labelled recoverable.
1300
- - **Peers**compact, read-only, every word the CLI's. It links to Crosslink and
1301
- never duplicates its editor: one boundary, one picture.
1302
-
1303
- ### Guards
1304
-
1305
- Five new agent files named explicitly in `verify-package.js` (floor 46 51,
1306
- skills unchanged at 38); five new contract-lint entries; a golden test comparing
1307
- `CHALLENGE_LENS_META` to `council.md`'s roster table; and one test per new read,
1308
- because `--json is not a summary` is drift no lint can catch.
1309
-
1310
- `css/panels/knowledge.css` is a new file, so it is `<link>`ed in `app.html` **and**
1311
- named in `verify-package.js` the manifest is the load order, and a file the
1312
- manifest forgot is a file the test suite never sees.
1313
-
1314
- ---
1315
-
1316
- ### v0.49.0 — the document is a folder, and the file is a build artifact _(2026-08-17)_
1317
-
1318
- `/orc-doc` only. No other lane changes, and **zero new agents**.
1319
-
1320
- Three quarters of what this release is about already existed: `orc doc plan`
1321
- already wrote one part file per section, the ids were already number-then-name,
1322
- the split already cut on `## ` alone, and `orc doc assemble` was already pure
1323
- Node **zero model tokens, and it always was**. Anyone who tells you this
1324
- release made compiling cheaper is selling something.
1325
-
1326
- What was wrong was the direction of the arrow.
1327
-
1328
- #### `sections/` is the source of truth
1329
-
1330
- `.work/` was scratch and `document.md` was the truth, so after the first
1331
- assemble every later change was *extract* (copy a section OUT of the monolith)
1332
- edit *splice* (write it back IN). The section files existed and were dead. A
1333
- resumed session, an update and a re-check all routed through the 10,000-line
1334
- file.
1335
-
1336
- Now each section lives in `sections/<NN>-<slug>.md` a real, visible folder you
1337
- can open, edit and read in a pull request — and **`document.md` is a build
1338
- artifact** that `orc doc compile` rebuilds from those files, for free, when you
1339
- ask. `orc doc split` goes the other way and recovers the sections from a
1340
- document a human reshaped by hand; **`split` then `compile` reproduces the file
1341
- byte for byte**, and there is a test.
1342
-
1343
- The join key is the **filename**. No comment markers inside the files: an HTML
1344
- comment is a lint error in this lane and mangles on a Notion or Google Docs
1345
- import, and the deliverable's cleanliness is the lane's entire product. A marker
1346
- that buys nothing costs the import.
1347
-
1348
- #### You can look before you buy the rest
1349
-
1350
- `orc doc compile --partial` writes exactly the sections that exist and **names
1351
- the rest outside the document**nothing is ever stubbed into the deliverable.
1352
- Paired with the new `doc_write_mode` (`ask` · `partial` · `all`, asked once per
1353
- run and stored), `orc doc plan --role write` returns **wave 1 only**, with
1354
- `more_waves: N`. You read what it wrote, and waves 2..N are bought only if wave 1
1355
- was right. That is the single biggest saving in the lane, and it has nothing to
1356
- do with the compile.
1357
-
1358
- #### A wave is a stop you can walk away from
1359
-
1360
- The write loop used to live in the orchestrator's head, and `/orc-doc`'s
1361
- `RESUME.md` sat in the document folder — where `orc resume` and `orc run list`
1362
- never look carrying a `## Where it stands:` line that the line-anchored parser
1363
- **could never match**, and no phase and no wave even if it had.
1364
-
1365
- All four are fixed. `RESUME.md` moves to `{run_dir}/{slug}/`, the line is at
1366
- column 0 and gains a phase D6 · wave 2 of 7` suffix (the byte-stable prefix is
1367
- untouched), and a test feeds the shipped template to the real `parseStands`. The
1368
- section files on disk ARE the progress, so `K of N` is **computed** by counting
1369
- waves whose sections are all hash-confirmed. A part on disk that no validated
1370
- return ever confirmed is `unconfirmed` exactly what a usage limit leaves — and
1371
- it is re-written, never shipped.
1372
-
1373
- #### The deliverable carries content only
1374
-
1375
- `> **Open:**` and `> **Assumption:**` lines are no longer written into your
1376
- document, and the section state no longer sniffs the body text for them. This
1377
- does not relax "never invent a fact"; it moves where the honesty is written down.
1378
- A gap goes to `orc doc log --kind gap` and lands in a derived `gaps.md`, and is
1379
- raised with you.
1380
-
1381
- `orc doc lint` gains `annotation-in-body` as an **error**, matching an exact,
1382
- narrow set of ORC's own markers and nothing else — a line of yours beginning
1383
- "Note:" is content and is never flagged. `compile` **reports** every match and
1384
- never silently strips one: we cannot tell whose line it is.
1385
-
1386
- #### A live bug, fixed by construction
1387
-
1388
- A slice covering two sections wrote **one** file, named after the first, while
1389
- `assemble` looked one up per outline id. The second section's file never existed:
1390
- if it was required, assemble refused forever; if it was optional, it silently
1391
- vanished from the deliverable. **One file per section** now, per slice entry, with
1392
- a regression test.
1393
-
1394
- #### A section too big for one file
1395
-
1396
- It splits **underneath** `sections/04-detailed-design/{00-head,01-data-model,…}.md`
1397
- — cut on its own `### ` headings, which `docScan` already collected and merely
1398
- filtered out. The reader never knows: the compiled document has exactly one `## `
1399
- for it, and `orc doc map`, `lint`, `ship` and `audit` are completely unchanged.
1400
- Five refuse-and-name rules make the nesting safe, and a changed sub-part is
1401
- detected on its own, so a re-check inside a 900-line section reads ~150 lines.
1402
-
1403
- **No new config key** for it: `doc_max_lines_per_agent` is already the threshold.
1404
-
1405
- #### The rest
1406
-
1407
- - **`doc_max_parallel` hard cap is now 2** (default 2, was 4/4). A larger value
1408
- is clamped and the clamp is announced.
1409
- - **`orc doc parts`** is the new wave-boundary read, and the one that works
1410
- before a single compile has ever run. `--confirm <ids>` is how a validated
1411
- return becomes a recorded hash.
1412
- - **`orc doc ship` refuses on a stale `document.md`**, naming the sections —
1413
- coverage-relative, one step earlier than `shipped-drifted`.
1414
- - **`orc doc audit`** gains `part-missing`, `part-orphan`, `part-misnumbered`,
1415
- `part-unconfirmed`, `subpart-bad-level`, `document-stale`,
1416
- `annotation-in-body`, `legacy-work` and `resume-misplaced`.
1417
- - **`orc doc outline --set` renames the files on disk** when a renumber moves
1418
- them, in the same step.
1419
- - **A checker now reads ONE bounded part file**, so there is no line arithmetic
1420
- anywhere in the check loop.
1421
- - The Docs panel gains a **Section files** card with nested sub-part rows, a wave
1422
- strip, a compile button and a migrate button. It derives nothing new: the CLI's
1423
- state words, verbatim.
1424
-
1425
- #### Nothing is lost on the way
1426
-
1427
- `doc.json` goes to `version: 2` and a v1 document migrates the first time you
1428
- touch it lazy, free, idempotent, non-destructive. `document.md` is **never
1429
- deleted** (it becomes the build artifact, and starts life fresh rather than
1430
- stale), a pending extract wins as the newer edit, an `> **Open:**` stub does not
1431
- survive, `RESUME.md` is moved and its prefix stripped, and an **unparseable**
1432
- document is REFUSED with `version` left at 1 — a guessed structure is worse than
1433
- none. `assemble`, `extract` and `splice` survive as thin aliases for one release,
1434
- with their exit codes preserved.
1435
-
1436
- ---
1437
-
1438
- ### v0.48.1 one file per thing, and a document that can be finished _(2026-08-16)_
1439
-
1440
- Two halves, deliberately kept separate so that **any** behaviour difference
1441
- observed after this release is attributable to the second one and to nothing
1442
- else.
1443
-
1444
- #### The panel is an architecture now
1445
-
1446
- `bin/webui/` was four monoliths: a 6 500-line `app.js`, a 2 500-line
1447
- stylesheet, a 1 700-line fixture module and two 800-key string tables. Any
1448
- change to one panel meant paging through all of it to find three places.
1449
-
1450
- It is now ~60 named files one per panel, one per CSS layer, one per i18n
1451
- namespace, one per fixture set — and the **filename is the load order**, so a
1452
- future session never has to reason about dependencies.
1453
-
1454
- - **Classic scripts, not ES modules,** and the constraint that decided it:
1455
- `serve.js` requires the per-launch token on every static request, and **an
1456
- `import` carries no query string**. A module graph would 401 on every import
1457
- unless static auth were weakened, which was not on the table. Classic scripts
1458
- also share one global lexical scope, so the split added no `import`/`export`
1459
- and changed no call site.
1460
- - **`serve.js` builds its static map from a one-time walk at boot.** A request
1461
- path is still a KEY LOOKUP in a frozen table, never a path join directory
1462
- traversal stays structurally impossible. Server-side code (`serve.js`,
1463
- `api.js`, `fixtures/`) is never served.
1464
- - **Token stamping is generic.** Naming two files was fine when there were two;
1465
- with ~55 the pattern has to be the rule, or the next `<script>` tag someone
1466
- adds 401s silently. A test parses `app.html` and asserts every reference comes
1467
- back stamped **and** resolves.
1468
- - **`06-responsive.css` and `04-motion.css` load last, and that is
1469
- load-bearing.** Several reduced-motion rules are deliberately not
1470
- `!important``.vault-pulse` and `.step-flow` are removed with
1471
- `display: none`, because capping an infinite animation to one iteration
1472
- freezes it mid-cycle so an equal-specificity rule loading afterwards would
1473
- win on order and switch the animation back on.
1474
- - **`verify-package.js` names every file AND asserts set equality** with the
1475
- directory, in both directions: the agent-file pattern, applied to the panel.
1476
- - The test suite is split to match (`test/cli/`, `test/lanes/`, `test/webui/`),
1477
- using an `appJs()` / `appCss()` helper that concatenates exactly what
1478
- `app.html` loads so a file the manifest forgot cannot hide behind a passing
1479
- suite.
1480
-
1481
- **No behaviour changed.** All 274 tests pass, all 17 panels render in both
1482
- themes and both languages with zero console errors, and the guided tour runs end
1483
- to end.
1484
-
1485
- #### `/orc-doc` has a finish line
1486
-
1487
- - **`orc doc next`** turns the pipeline from something the orchestrator
1488
- REMEMBERS into something the CLI COMPUTES — the Flow-stepper shape, and for
1489
- the same reason: D6–D9 was prose a session had to hold in its head across a
1490
- resume that might be months later in a fresh context. Exit **0** = an action
1491
- is available (`command`, plus `paid` so a caller knows button vs copy-able
1492
- command), **1** = waiting on a human decision, **named** in `blocked_by`,
1493
- **2** = unknown slug.
1494
- - **`orc doc ship` records delivery as a DECISION** (`/orc-pact`'s rule) while
1495
- the resulting state stays **COMPUTED** (`/orc-challenge`'s rule). `--where`
1496
- has **no default** — "shipped" with nowhere to point at is not a fact, it is a
1497
- feeling and shipping an incomplete document needs `--force --reason`,
1498
- recorded verbatim. `unship` needs a reason and keeps the old record in
1499
- `ship_history[]`.
1500
- - **`shipped-drifted` names the sections that moved,** by diffing the recorded
1501
- per-section hashes against the live map. Coverage-relative, the
1502
- `computeWikiFreshness` lesson applied to a document: a whole-file "something
1503
- changed" cannot tell you what to re-read. It exits **1**, because the document
1504
- moved after it was delivered and that is work.
1505
- - **`orc doc audit`** reports every drift class from disk an extract never
1506
- spliced back, an extract whose section moved under it, a heading a hand edit
1507
- deleted or added, a target that no longer matches the file, a reference file
1508
- that moved, a cycle count that disagrees with itself each with a fix command
1509
- and the panel that can clear it. A hand-edited section is **reported and never
1510
- counted as a finding**: flagging it would teach people to stop editing their
1511
- own document. `orc doctor` gains a `doc-drifted` finding routed to Docs.
1512
-
1513
- #### And it remembers what you asked for
1514
-
1515
- This was a **data** gap, not a rendering one. `created_at` existed and
1516
- `orc doc show --json` never emitted it; `context.md` and `context-sources.md`
1517
- were files the CLI never opened; and what the user actually ASKED FOR, in order,
1518
- across every session, lived nowhere at all.
1519
-
1520
- - **`orc doc log` / `journal`** record and serve it. The journal merges four
1521
- sources into one chronological array with the provenance of every row attached
1522
- `recorded` (the user's own words, verbatim), `derived` (a cycle, a ship
1523
- record), `observed` (a section that turned `user-edited`) and **it never
1524
- invents an entry**: a cycle that ran with nothing logged renders as an explicit
1525
- gap, never a plausible reconstruction from file mtimes. The `/orc-pact`
1526
- UNCHECKABLE rule: not knowing is an answer, and faking it teaches people to
1527
- distrust the rows that are real.
1528
- - **`orc doc context`** returns the frozen brief — the verbatim request first,
1529
- because that is the memory-regain payload plus the D2 reference table with a
1530
- live state per file: `ok`, `MISSING`, `SOURCE-DRIFTED`. A source is stale
1531
- only when THAT FILE moved, never because the repository did, and it is a
1532
- **warning, never an error**: a frozen context is *supposed* to be old.
1533
- - **`orc doc read`** is a reader for the HUMAN — and the rule table says out
1534
- loud that the orchestrator never runs it, registered as a contract token so
1535
- the sentence cannot quietly disappear.
1536
- - **The Docs panel is rebuilt around this: MEMORY FIRST, state second.** The
1537
- header strip, the brief, the reference files and the journal come before the
1538
- ribbon because a user coming back after three weeks did not come back to ask
1539
- what state the document is in.
1540
-
1541
- #### One more way in
1542
-
1543
- D4 and D5 gain a `RETURN-TO` suspend into **`/orc-grill`** gated on all
1544
- three of the `_shared/lane-suspend.md` tests (a DECISION not a fact, a
1545
- PREREQUISITE that changes the option set, a SUBTREE with more than one question
1546
- hanging off it), or it asks inline. The snapshot is **run state, never the
1547
- deliverable**, so hard rule 10 still holds; and on resume the lane re-writes
1548
- `.current` and touches the trace file in the same step, because `/orc-grill`
1549
- deleted the pointer at its own `FINISH`. Two traces for one document is
1550
- correct two lanes ran.
1551
-
1552
- ---
1553
-
1554
- ### v0.48.0 a document long enough to end a session, written anyway _(2026-08-13)_
1555
-
1556
- **`/orc-doc`** writes the long document — a PRD, a TSD, a cross-team
1557
- collaboration agreement, a status report or a workflow/runbook as portable
1558
- Markdown, and it survives the session that started it.
1559
-
1560
- Two contracts hold the lane together, and everything else serves them:
1561
-
1562
- > **The orchestrator never reads the document body.** It knows the document only
1563
- > through the CLI's derived section map and through what the agents it
1564
- > dispatched report back. **a lane that reads its own document** has broken this
1565
- > contract.
1566
-
1567
- > **The context is gathered once and frozen.** A resumed session reads
1568
- > `context.md` from disk; it never re-interviews the user for what session 1
1569
- > already settled. **a lane that re-asks a frozen question** has broken this
1570
- > contract.
1571
-
1572
- - **The token architecture is the lane.** A 900-line TSD is ~30k tokens; read it
1573
- three times and the session is over. So nothing that holds context ever holds
1574
- the document. `orc doc map` derives a section map — heading, absolute line
1575
- range, SHA-256, computed state each writer owns **one `.work/` part file**,
1576
- and each checker reads **one line range** with `Read(offset, limit)`. On a
1577
- 10,000-line, 40-section document that is ~750 lines of orchestrator context
1578
- instead of 20,000+, and a re-check after an edit re-dispatches only the
1579
- sections whose hash moved. *The hash is what turns a re-check from a full pass
1580
- into a diff.*
1581
- - **Line arithmetic is the CLI's and nothing else's.** It is the one job a model
1582
- is guaranteed to get wrong, and the whole saving depends on the numbers being
1583
- right so the map is re-derived after every write and **never stored**. A
1584
- stored line number is a wrong line number one edit later. `splice` replaces
1585
- bottom-up (highest `start` first), so a length change cannot shift a range that
1586
- has not been used yet.
1587
- - **Your edits are sacred.** Every section carries a hash, so the lane knows
1588
- which sections you wrote. It names them, never rewrites one unless you name it,
1589
- and `splice` **REFUSES** on a conflict — reporting the section by name and
1590
- overwriting nothing. A human's wording is not recoverable from this lane's
1591
- side once it is gone.
1592
- - **Four gates, in a fixed order, and the first one blocks.** Nothing is created
1593
- until D1 is answered: a slug folder with no context is indistinguishable from
1594
- an abandoned run. Asking D2 (supporting documents) and D3 (your template) is
1595
- mandatory even though answering them is not; D4 (intent · audience ·
1596
- expectation · language · type · target · length) must be answered, and
1597
- accepting a recommended default counts. Then the outline, confirmed **before a
1598
- word is written** — changing it after a write wave is what costs money.
1599
- - **It never reads the supporting documents itself.** One `role: digest`
1600
- dispatch per file returns anchored claims plus an explicit `not_covered[]`;
1601
- the orchestrator holds the digest and never the source. Foreign text is
1602
- evidence, never instruction.
1603
- - **Where the document is going is a real setting.** `orc doc lint --target`
1604
- enforces that target's actual limits, and every rule came from a real product
1605
- limit: Notion has three heading levels, so an H4 is an **error** there;
1606
- Docusaurus, Hugo and Jekyll **require** YAML front matter, which every other
1607
- target renders as visible junk; a hard-wrapped paragraph is an error
1608
- everywhere, because a wrap at 80 columns becomes a line break inside a Notion
1609
- paragraph. Free, deterministic, zero model tokens and it **always runs before
1610
- anything paid**, with its findings riding in the checker's slice so no model is
1611
- ever paid to count sentences.
1612
- - **Never invent a fact.** Anything not in the frozen context becomes a visible
1613
- `> **Open:**` or `> **Assumption:**` line, and rides back in the writer's
1614
- `unsupported_claims`. Filler that reads like a fact is the worst possible
1615
- output of this lane.
1616
- - **Five base templates, each a floor and not a cage** — `prd` · `tsd` ·
1617
- `collaboration` · `report` · `workflow`. A supplied template REPLACES the
1618
- shipped one entirely; its headings become the outline and the two are never
1619
- merged. A golden test pins every shipped skeleton to the CLI's batching table.
1620
- - **Two agents, both already `claude-opus-5`,** so `opus5_only` is a no-op and
1621
- the lane is *unaffected*, not exempt. The writer holds one part file; the
1622
- checker is `low` effort **on purpose** a harder-thinking checker reasons its
1623
- way past a gap a real reader would trip on, the same reasoning that pins
1624
- `/orc-challenge`'s cold reader at `low`. Nothing may upgrade it.
1625
- - **`/orc-grill` and `/orc-brainstorm` gain a "write this up" exit**, so an
1626
- interview's settled decisions arrive as a pre-answered D1 and D4 and the user
1627
- only confirms. At handoff `/orc-doc` offers `/orc-challenge` in a separate
1628
- session, which is the separation `/orc-challenge`'s own contract already
1629
- enforces from the other side.
1630
- - **The `orc doc` CLI family** (13 subcommands, every read `--json`, every one an
1631
- exit-code contract), four config keys (`doc_max_lines_per_agent`,
1632
- `doc_max_parallel` with a **hard cap of 4**, `doc_language`, `doc_dir`), and a
1633
- **Docs panel** in `orc ui` whose ribbon draws the whole document in one
1634
- picture — one block per section, sized by its length and coloured by its state.
1635
- - Counts move: **skills 37 38 · commands 28 29 · agent files 44 → 46.**
1636
-
1637
- ---
1638
-
1639
- ### v0.47.0 the lane that refuses to produce _(2026-08-12)_
1640
-
1641
- **Every other lane in ORC and nearly every other skill in the ecosystem —
1642
- produces. This one refuses to.** `/orc-challenge` grades a finished artifact,
1643
- writes down what is wrong, and then stops and makes the user go away and fix it
1644
- somewhere else. The stopping is not friction: **the separation is the measuring
1645
- instrument.**
1646
-
1647
- **The one-sentence contract: ORC judges, the user fixes, ORC re-judges — and ORC
1648
- never fixes what it judged.** A session that just wrote the fix will grade its
1649
- own homework and it will always pass. That registers as the third member of an
1650
- existing pair`a lane that answers its own interview question` (v0.42.0),
1651
- `a lane that picks its own favourite` (v0.45.0), and now **`a lane that fixes
1652
- what it judged`**. Same split every time: facts and findings are ORC's, the work
1653
- and the decision are the user's.
1654
-
1655
- **Rule 0 precedes every other rule: it never guesses the goal.** A finding is
1656
- only a finding relative to a goal the same TSD is *finished* for one purpose
1657
- and nowhere near done for another. A lane that assumes will attack the wrong
1658
- thing with total confidence, and every one of its findings will be *defensible*,
1659
- which is worse than being obviously wrong: the user spends three iterations
1660
- fixing what did not matter. So intake ASKS, in ONE round, for the goal, the
1661
- audience, what "done" means, the template, and where the fixed version will go —
1662
- and freezes them to `goals.md`. **`orc challenge init` has no default for
1663
- `--goal`, `--audience` or `--done-means`**, so a run that tried to skip the round
1664
- fails at the CLI by name instead of inventing a purpose. Every finding must name
1665
- which goal element it `serves`; one that cannot is **dropped**, which is the
1666
- mechanism that stops a large context window from reviewing the entire universe.
1667
-
1668
- **Three agents, and they are three different INSTRUMENTS, not three tiers.**
1669
-
1670
- - **`orc-challenge-reader-opus-5-low`** the cold read. Tools: `Read` and
1671
- nothing else. It is given the artifact and the audience line, never the goal,
1672
- and it answers questions FROM the artifact rather than reviewing it. Returns a
1673
- scored questionnaire (`8/12`). **`low` effort is a measurement choice, not a
1674
- cost one:** a harder-thinking reader reasons around exactly the gaps this
1675
- exists to find, so a stronger configuration is a WORSE instrument.
1676
- - **`orc-challenge-judge-opus-5-high`** grades against the frozen template and
1677
- goal. Its slice is **SEALED**: paths and finding ids only, never prose from the
1678
- session, never a diff summary, never "the user says they fixed #4". A fix is a
1679
- claim; a verdict is evidence. **It cannot declare a pass** — `orc challenge
1680
- record` computes that, which removes leniency as a possibility.
1681
- - **`orc-challenge-advisor-opus-5-med`** dispatched only on a FAIL (advice on a
1682
- passed artifact is invented work and it costs money). Twelve findings are
1683
- usually three causes: it groups them by root cause, orders them with the
1684
- dependency reason, and flags the ones that are really unmade DECISIONS. No
1685
- prose, no diffs handing over wording is fixing by another name.
1686
-
1687
- All three are already `claude-opus-5`, so `opus5_only` is a no-op here: zero new
1688
- pairs, no rename churn. The lane is **unaffected, not exempt**.
1689
-
1690
- **`orc challenge lint` the deterministic engine, and it costs zero model
1691
- tokens.** Structure against the frozen template (missing / out-of-order /
1692
- invented / empty-ceremony sections, table column drift, untagged code fences,
1693
- links and `file:line` anchors that do not resolve) plus prose (acronyms used
1694
- before they are defined, sentences over 25 words with a p50/p90 distribution, a
1695
- passive-voice percentage, curated idioms and phrasal verbs, ambiguous
1696
- quantifiers, bare-pronoun openers, placeholder markers, a Flesch–Kincaid
1697
- estimate). **Sentences are measured over PARAGRAPHS, not lines**a hard-wrapped
1698
- 43-word sentence is still a 43-word sentence, and splitting at the newline is how
1699
- a length check silently passes every wrapped document. Two honesty rules are
1700
- printed by the command itself: it is a SIGNAL, not a verdict, and it is
1701
- English-specific and heuristic. Its real payoff is that `lint.json` rides in the
1702
- judge's slice, so the judge never spends tokens counting. It is useful with no
1703
- cycle, no model and no ORC run at all: `orc challenge lint README.md`.
1704
-
1705
- **Conservation — nothing evaporates.** Every finding from iteration N−1 appears
1706
- in N with exactly ONE outcome (`resolved` · `still-open` · `superseded` ·
1707
- `withdrawn` · `accepted`) and a reason; below 100% coverage the verdict is
1708
- malformed and `record` rejects it **naming the missing ids**. A silently dropped
1709
- finding is indistinguishable from a fixed one, and that is the classic way a
1710
- review cycle appears to converge. `record` also rejects an unknown carry id, a
1711
- reasonless withdrawal, an uncited supersede, an **ignored rebuttal**, and a
1712
- **silent dimension** `NOT-CHECKED` with a reason is allowed, silence is not.
1713
-
1714
- **Two escape valves, because a loop with no exit is a trap.** `orc challenge
1715
- accept <slug> <id> "reason"` — the finding stops blocking immediately and stays
1716
- visible forever in the report with the reason; never automatic (the `/orc-pact`
1717
- retirement rule). `orc challenge rebut <slug> <id> "reason"` the next judge
1718
- must answer it explicitly, `withdrawn` with an admission or `upheld` with new
1719
- evidence, and a verdict that ignores it is rejected. Without it, one wrong
1720
- finding loops forever and the user's only move is to give up.
1721
-
1722
- **Convergence, not a cap.** There is deliberately no loop cap and no config key
1723
- for one: every other loop in ORC runs inside a single session and costs tokens
1724
- per turn, but here each turn is a separate human sitting down to work, and a cap
1725
- that refused on iteration 6 would be refusing to review a hard document. It
1726
- reports `stalled` instead once, with three honest options.
1727
-
1728
- **Seven states, all COMPUTED, none stored**`AWAITING-JUDGE`, `AWAITING-FIX`,
1729
- `AWAITING-RECHECK`, `PASSED`, `STALE-PASS` (honest, not a failure the
1730
- `UNCHECKABLE` precedent), `MISSING-REVISION`, and `TAMPERED` (a verdict file
1731
- changed after it was recorded: reported, never silently re-graded). Two flags
1732
- ride alongside rather than becoming states of their own, because a state that
1733
- means two things is a state that lies: `stalled` and `no_template`.
1734
-
1735
- **The resumed session never asks where the fix went.** `revision_mode` is
1736
- declared at intake and restated in a `Where to put the revised version` block in
1737
- every fix brief; `orc challenge diff` resolves the expectation first and then
1738
- reports which carried findings the change actually TOUCHED
1739
- coverage-relative, the `computeWikiFreshness` lesson applied to findings, and a
1740
- hint for the human that is **never an input to the judge**. When the declared
1741
- path is not there, `MISSING-REVISION` **lists candidates and never adopts one**:
1742
- picking the closest-looking file would point the judge at the wrong artifact and
1743
- produce a page of confident, useless findings. The escape (`orc challenge expect
1744
- --set`) is a recorded command.
1745
-
1746
- **The CLI half: 12 subcommands, every read with an exit-code contract and
1747
- `--json`.** `list` (0/1/3) · `status` (0/1/2/3) · `show` · `diff` (0/1/2/3) ·
1748
- `expect` · `lint` (0/1/2) · `outline` · `record` (the GATE, not a store) ·
1749
- `accept` · `rebut` · `template`/`goals` (re-freezing is a recorded event that
1750
- needs a reason, and prior iterations keep their stamp) · `report` (derives
1751
- `CHALLENGE.md`, plus the final report on a pass). `challenge.json` has exactly
1752
- one writer, and it is never a model.
1753
-
1754
- **The `orc ui` Challenge panel** renders it and decides nothing about it: the
1755
- goal block above everything, the state chip with its ONE next action inline, an
1756
- iteration timeline whose **geometry is solved from the box size** (with a dashed
1757
- version break wherever a goal or template was re-frozen), the convergence chart
1758
- stacked by severity, a dimension strip where `NOT-CHECKED` keeps its slot and
1759
- carries its reason, the cold reader's score, and the findings with their accept /
1760
- rebut buttons. **A free action gets a button, a paid action gets a copy-able
1761
- command** running an iteration has no write route at all. `--fixtures` carries
1762
- one of every state including the ugly ones, and a test asserts it.
1763
-
1764
- **Four config keys**, all `common`: `challenge_pass_severity` (default `p1`),
1765
- `challenge_stall_after` (3), `challenge_reader` (`on`; `off` makes D4 report
1766
- `NOT-CHECKED` with that reason, never silently), and `challenge_gate` (`warn`;
1767
- there is deliberately no `block` the `/orc-pact` precedent). Deliberately NOT
1768
- added: a same-session escape hatch (that is how the premise dies), any model or
1769
- effort key, and any loop cap.
1770
-
1771
- **Seams:** `/orc` prints one preflight line when it is about to build from a
1772
- document that has not passed its own review; `/orc-analyze` prints the cycle
1773
- state at Phase A (the two compose in one order challenge it, then analyze it);
1774
- `/orc-pact` gains the finding-that-is-really-a-decision harvest; intake's "I
1775
- don't know yet" suspends into `/orc-grill` and comes back; `/orc-export` can
1776
- carry a PASSED cycle as portable evidence.
1777
-
1778
- **Trace:** lane `challenge`, **Iterative tier** (one packet per completed
1779
- iteration), and a new `CHALLENGE iter=…` verb whose line the CLI assembles so
1780
- nothing composes a second wording for the same number. Several trace files for
1781
- one cycle is CORRECTseveral sessions ran.
1782
-
1783
- ### v0.46.1 see a lane run before you pay for one _(2026-08-12)_
1784
-
1785
- **The docs answered "what is ORC" four times and never answered "what does a
1786
- lane look like when it runs".** Rides on top of v0.46.0, below.
1787
-
1788
- **`mock-run/` — one written walkthrough per lane.** What you type, what ORC
1789
- prints back, what lands on disk, in easy English, all on one shared example
1790
- project. Nothing was executed to make them: they exist so nobody has to spend
1791
- tokens to find out what a command does. Start at `mock-run/INDEX.md`.
1792
-
1793
- **`orc mock-run list | show <slug>`** reads the same catalogue from the
1794
- terminal, and **`orc ui` grows a Mocked Skill Use panel** — every walkthrough,
1795
- grouped, searchable, with a reading pane. The catalogue is DERIVED from the
1796
- files on disk (title from the heading, lane from whether the command really
1797
- exists), so adding a walkthrough needs no list edited anywhere; the panel
1798
- renders it and decides nothing about it, exactly like the Flow stepper.
1799
-
1800
- **The README is 928 lines shorter and current.** It was still describing an
1801
- older payload the six v0.46.0 lanes were missing from the panel list, the
1802
- config table showed 11 of 52 keys, and the eval section quoted a round from four
1803
- releases ago. History moved here to `CHANGELOG.md`, which is now what `orc
1804
- changelog` fetches: a README carrying one entry would have answered a user ten
1805
- releases behind with a single line. The detail that used to bloat it lives in
1806
- `guides/configuration.md` and `guides/model-selection.md`.
1807
-
1808
- **Two real bugs found while building it.** The panel's markdown renderer looped
1809
- forever on a malformed table row (the paragraph branch is the fall-through, so a
1810
- line every branch declined never advanced the cursor), and an upgrade modal
1811
- showed the newest release with `## Earlier releases` glued to the end of it —
1812
- an entry now stops at the next section heading, not just at the next release.
1813
-
1814
- ---
1815
-
1816
- ### v0.46.0 a lane that remembers, a lane that declines, and a lane that measures _(2026-08-10)_
1817
-
1818
- **The ecosystem has a thousand skills that GENERATE.** This release builds the
1819
- three things a generator structurally cannot be, plus the wiki work that pays for
1820
- them and the panels that make them visible. Six new lanes, one new agent, and the
1821
- biggest cost cut available to ORC so far.
1822
-
1823
- **`/orc-pact` — the lane that remembers.** `/orc-grill` and `/orc-brainstorm`
1824
- already settle constraints, and a plan already carries them into every executor
1825
- slice. Then the run ends and they evaporate. The pact is a ledger that outlives
1826
- the run, with four states that are **computed on read, never stored**: HOLDING,
1827
- **DRIFTED** (commits since it was verified touched the files it anchors —
1828
- coverage-relative, so a promise about payments does not fall into doubt because
1829
- the README changed), **UNCHECKABLE** (nothing cheap proves it the honest state,
1830
- and it never counts against you), and BROKEN. It never invents a promise: every
1831
- entry records where it came from. It never retires one for you. And the payoff is
1832
- automatic at planning time, a drifted promise whose files your plan is about to
1833
- touch is injected into the planner as a constraint, so last month's decision
1834
- constrains this month's work. `PACT.md` is a committed, PM-readable file at your
1835
- project root, rendered by the CLI from the ledger so the two can never disagree.
1836
-
1837
- **`/orc-boundary` the lane that declines.** Every skill you can install assumes
1838
- the answer to *"should the agent do this?"* is yes; agents spend 5×–50× longer
1839
- than human experts on a task, and most of the excess goes into attempts that were
1840
- never going to succeed. Three verdicts per area — EXECUTE, ESCALATE, REFUSE — each
1841
- derived from four questions answered from things already on disk: can it verify
1842
- itself, does it know this area, is the change reversible, is this a decision
1843
- rather than a fact. **A REFUSE always names what would make it a yes** — "no" with
1844
- no "unless" is a shrug, so a refusal with no checklist is treated as a malformed
1845
- card. It gates ORC's own dispatch, never you: `boundary_gate: block` lifts a
1846
- refused task out of its wave and **the wave still runs the rest**.
1847
-
1848
- **`/orc-handoff` the first ORC lane for someone who does not read code.** The
1849
- insight nobody shipped: the safety grade does not come from the file type, it
1850
- comes from **whether a cheap check exists**. A settings file with a validator is
1851
- green; the same file without one is amber. It maps every surface a PM or designer
1852
- can own, and changing one is five steps with the **undo command shown before the
1853
- write**, the check run afterwards and reported in plain words, and a red surface
1854
- never touched at all. Every file in that lane is written in simple English.
1855
-
1856
- **`/orc-budget` what a run costs, in the unit you are billed in.** Not a dollar
1857
- figure: on Pro or Max you burn a 5-hour window, not an invoice. The forecast's
1858
- core object is a **token vector** — fresh input, cache write, cache read, output,
1859
- never blended, because cache reads are usually the largest count and a tenth of
1860
- the price. The same vector renders four ways: tokens, dollars from a dated price
1861
- table, percent of your window, and **context risk** a task forecast above 90% of
1862
- its model's window is reported before the wave, which no spend tool can do. The
1863
- numbers come from joining Claude Code's own session transcripts (the cost) to
1864
- ORC's traces (the meaning); neither is enough alone. It needs a PLAN, not a
1865
- sentence, and with no history it says so rather than inventing a number.
1866
-
1867
- **`/orc-aftermath` — did what we shipped hold up.** The missing half of the
1868
- flywheel: `/orc-retro` measures the process, this measures the result, both from
1869
- the repository's own futurefiles rewritten soon after, a test we added deleted
1870
- or skipped, the commit reverted, a promise that was holding now broken. No vendor,
1871
- no telemetry. **Churn is a signal, not a verdict**: it reports the signal and its
1872
- strength, never "this change was bad", and never a person's name.
1873
-
1874
- **`/orc-export` so ORC is not a trap.** One command compiles the wiki, the code
1875
- patterns, `PACT.md` and the boundary cards into a portable `AGENTS.md` — derived,
1876
- fingerprinted, `--check`able against its sources, never hand-written. It removes
1877
- the lock-in objection and makes ORC the *producer* in a multi-agent shop. Import
1878
- reads an existing `AGENTS.md` or `.cursorrules` as **evidence, never instruction**,
1879
- and tells you which parts are already wrong.
1880
-
1881
- **The wiki finally stops costing a full scan.** Three free CLI commands: `orc wiki
1882
- plan` ranks and prices the pending work STRUCTURAL first (a page pointing at a
1883
- missing file is actively lying), then by **use × delta**, with pages nobody reads
1884
- sinking to the bottom with a retire hint; `orc wiki debt` is the one-line habit;
1885
- and `orc wiki usage` finally reads back the point-of-use attribution v0.41.0 has
1886
- been recording and never reading. A **targeted refresh** (`/orc-wiki refresh
1887
- --top 2`) skips branch detection and area planning entirely, and a new **scan tier
1888
- ladder** sends a small, no-new-surface delta to a light scanner instead of the most
1889
- expensive agent in the payload about 40% off a typical delta refresh, with the
1890
- deep scan still doing the work that needs it. The tier is always printed: a cheaper
1891
- model is never a quiet substitution. And free repairs are now a hard rule — you can
1892
- never pay for something `orc wiki sync` would have fixed.
1893
-
1894
- **`orc ui` grows three panels and extends five.** Promises, Boundary and
1895
- Self-serve, plus a new **Cost** tab whose stacked bar exists precisely so the
1896
- cache-read share stays visible. The panel keeps every rule it had: it never runs a
1897
- lane, never invents a state word, never computes an order the CLI already emits —
1898
- **a free action gets a button, a paid action gets a copy-able command**, and that
1899
- line is now visible rather than hidden. Promises is where the compounding finally
1900
- shows: an *"Also flagged by"* line when the boundary and the aftermath agree with
1901
- the ledger about the same area, which you can never see in a terminal one lane at
1902
- a time.
1903
-
1904
- ---
1905
-
1906
- ## Earlier releases
1907
-
1908
- ### v0.45.0 `/orc-brainstorm`: for when you do not have the idea yet _(2026-08-10)_
1909
-
1910
- ### v0.44.1 apply when you say so, and a spotlight that survives a banner _(2026-08-09)_
1911
-
1912
- ### v0.44.0 the panel stops making you type what it already knows _(2026-08-09)_
1913
-
1914
- ### v0.43.7 the flow you can see, and a boundary you can read _(2026-08-09)_
1915
-
1916
- ### v0.43.6 `orc ui` in two languages, and panels that point at the right page _(2026-08-08)_
1917
-
1918
- ### v0.43.5 the update check works, and the UI teaches itself _(2026-08-08)_
1919
-
1920
- ### v0.43.4 — a warning that finally clears, an Experiment panel, crosslink from the UI _(2026-08-08)_
1921
-
1922
- ### v0.43.3 `orc ui`: it tells you about updates, and 36 keys stop being a wall _(2026-08-08)_
1923
-
1924
- ### v0.43.2 — `orc ui`: boxes stop colliding, because the container owns the gap _(2026-08-08)_
1925
-
1926
- ### v0.43.1 the panel's stylesheet and script actually reach the browser _(2026-08-08)_
1927
-
1928
- ### v0.43.0 — `orc ui`: a control panel for everything that is not ai _(2026-08-08)_
1929
-
1930
- ### v0.42.0 Say what you mean, see what it costs, find your way back _(2026-08-08)_
1931
-
1932
- ### v0.41.0 A wiki that can tell you it is fresh, and TDD only where it can fail _(2026-08-06)_
1933
-
1934
- ### v0.40.0 Gotchas: repair memory that outlives the run _(2026-08-06)_
1935
-
1936
- ### v0.39.0 — The read ladder, and foreign input that is evidence rather than instruction _(2026-08-06)_
1937
-
1938
- ### v0.38.1 — `orc doctor --json` + handoff carry-over that says what is re-derived _(2026-08-06)_
1939
-
1940
- ### v0.38.0 `/orc-quick`: the quick lane, and the gate no config can collapse _(2026-08-05)_
1941
-
1942
- ### v0.37.0 Stacked pull requests: a measured ship gate + two standalone lanes _(2026-08-03)_
1943
-
1944
- ### v0.36.0 `opus5_only`: one model for every role, not just executors _(2026-08-02)_
1945
-
1946
- ### v0.35.0 — `opus5_executor_only`: one model, effort as the cost dial _(2026-08-02)_
1947
-
1948
- ### v0.34.8 — `orc pattern status` rejects a language key the payload has never heard of _(2026-08-01)_
1949
-
1950
- ### v0.34.7 DIY: a usable status contract, and compile docs that match the compiler _(2026-08-01)_
1951
-
1952
- ### v0.34.6 Analyze: the evidence gate now covers the rows a good analysis produces _(2026-08-01)_
1953
-
1954
- ### v0.34.5 Wiki: stop losing tags silently, let a delta clear its own delta _(2026-08-01)_
1955
-
1956
- ### v0.34.4 Planner: scorable facets, and TDD rules scoped to reality _(2026-08-01)_
1957
-
1958
- ### v0.34.3 Slice boundary: the worktree, not the editor _(2026-08-01)_
1959
-
1960
- ### v0.34.2 — Trace subsystem: the pointer clobber, and a writer contract that holds _(2026-08-01)_
1961
-
1962
- ### v0.34.1 Install integrity: run state survives `orc update` _(2026-08-01)_
1963
-
1964
- ### v0.34.0 Opus 5: top scoring band, every core role, medium-effort session tier _(2026-07-25)_
1965
-
1966
- ### v0.33.0 Knowledge deepening + verification revamp _(2026-07-25)_
1967
-
1968
- ### v0.32.0 — Trace revamp: narration is dispatched, not remembered _(2026-07-24)_
1969
-
1970
- ### v0.31.0 — Execution-integrity revamp: plan handoff, attributable traces, facet scoring _(2026-07-23)_
1971
-
1972
- ### v0.30.0 Scoring revamp, Fable 5 role override, tier-aware guards, `orc onboarding` _(2026-07-23)_
1973
-
1974
- ### v0.29.0 Drift-prevention hardening: install manifest + prune, `orc doctor`, a real test suite _(2026-07-22)_
1975
-
1976
- ### v0.28.1 — Defect fixes: package encoding, trace event routing, count/doc drift _(2026-07-22)_
1977
-
1978
- ### v0.28.0 Run integrity: rich full-lane traces, deterministic wave stop, visible knowledge gates _(2026-07-21)_
1979
-
1980
- ### v0.27.0 `/orc-poly`: plan one change across two-or-more repos without drift _(2026-07-20)_
1981
-
1982
- ### v0.26.0 Test-gen output pinned to a visible `test-generator/<change-slug>/` deliverable _(2026-07-19)_
1983
-
1984
- ### v0.25.1 Eval report: the full 17-lane suite graded against the v0.25.0 payload _(2026-07-18)_
1985
-
1986
- ### v0.25.0 Deterministic artifact detection: a generated wiki/pattern is never missed _(2026-07-18)_
1987
-
1988
- ### v0.24.0 Crosslink fused into wiki generation: always-on, per-scan-task, never wiped _(2026-07-18)_
1989
-
1990
- ### v0.23.0 — Trace fix: SPAWN restored on the `Agent` tool, stale runs rotate to fresh files _(2026-07-18)_
1991
-
1992
- ### v0.22.0 `/orc-learn`: per-feature onboarding docs learning.md + knowledge.md, wiki-deep, git-ignored _(2026-07-17)_
1993
-
1994
- ### v0.21.0 Statusline shows live subscription usage: 5h weekly, official numbers _(2026-07-16)_
1995
-
1996
- ### v0.20.0 One source of truth: generated executor agents + shared cross-lane contracts _(2026-07-16)_
1997
-
1998
- ### v0.19.0 Thin spines: skill compaction, budget lint, and a trace that logs every phase _(2026-07-16)_
1999
-
2000
- ### v0.18.0 `orc wiki sync`: the wiki registers itself a paused scan is no longer an invisible wiki _(2026-07-15)_
2001
-
2002
- ### v0.17.3 Trace the wiki consult: Phase 1 now logs whether the run grounded in the wiki (and if it was stale) _(2026-07-14)_
2003
-
2004
- ### v0.17.2 Behavior-trace logging is permanent + the trace folder is now created deterministically _(2026-07-14)_
2005
-
2006
- ### v0.17.1 Complete cross-repo crosslink setup guide in the orc-wiki README _(2026-07-14)_
2007
-
2008
- ### v0.17.0 `orc crosslink`: cross-repo wiki references advisory boundary contracts _(2026-07-14)_
2009
-
2010
- ### v0.16.1 Interactive `orc diy` composer + numbered picks in `orc config` _(2026-07-14)_
2011
-
2012
- ### v0.16.0 `/orc-diy`: build your own lane CLI-composed flow, compiled, hard-gated _(2026-07-14)_
2013
-
2014
- ### v0.15.0 Wiki v2: evidence-anchored docs · per-file staleness registry · integrity gate _(2026-07-14)_
2015
-
2016
- ### v0.14.0 Postgres data-access playbook: cross-cutting query grounding _(2026-07-13)_
2017
-
2018
- ### v0.13.0 `/orc-claude`: local CLAUDE.md builder fenced sections, fingerprint refresh, zero questions _(2026-07-12)_
2019
-
2020
- ### v0.12.0 — Lossless context-combiner: conservation gate · overlap taxonomy · evidence freshness _(2026-07-12)_
2021
-
2022
- ### v0.11.0 — `/orc-fast`: knowledge-gated speed lane + wiki freshness infrastructure _(2026-07-12)_
2023
-
2024
- ### v0.10.1 README: a fuller "Why ORC exists" _(2026-07-12)_
2025
-
2026
- ### v0.10.0 `/orc-ultra`: max-effort advisor + three judgment gates for ultra-complex work _(2026-07-12)_
2027
-
2028
- ### v0.9.0 Trust-but-verify the analyst→planner chain: quote-anchored evidence · coverage gate · anchored judgment _(2026-07-12)_
2029
-
2030
- ### v0.8.1 /orc-retro delivers upstream: PR/issue to the ORC repo, channel-gated _(2026-07-12)_
2031
-
2032
- ### v0.8.0 Close the loop: grounded intake · scoring anchors · OUTCOME marker · /orc-retro trace miner · eval harness _(2026-07-12)_
2033
-
2034
- ### v0.7.0 — Evidence everywhere: grounded plans · verbatim proof · anchored findings · contract lint · trace fixes _(2026-07-12)_
2035
-
2036
- ### v0.6.0 P0–P3 ladder · house rules · deep playbooks + wired gates · 3 new languages · FE rule packs · security pass _(2026-07-11)_
2037
-
2038
- ### v0.5.1 Statusline false-degrade fix _(2026-07-11)_
2039
-
2040
- ### v0.5.0 Code-pattern findings: executors match your house style, invariants always enforced
2041
-
2042
- ### v0.4.5 Rewrite weak worker descriptions (the real score lever)
2043
-
2044
- ### v0.4.4 Act on external review: raise sub-70 workers, fix cross-spine paths
2045
-
2046
- ### v0.4.3 `orc-analyze`: trim description under the 1024-char skill-spec limit
2047
-
2048
- ### v0.4.2 External-review pass: worked examples + sharper mini-analyst activation
2049
-
2050
- ### v0.4.1 `orc-mini`: faster, safer fast-lane smoke gate, opt-in tests, trimmed ceremony
2051
-
2052
- ### v0.4.0 Opt-in Phase 6.5 Test Authoring (writes test cases, never runs them)
2053
-
2054
- ### v0.3.0 Opt-in behavior-trace logging + claimed-vs-actual model verification
2055
-
2056
- ### v0.2.4 — `orc-analyze`: gather anchored adjacent-scope context (non-actionable)
2057
-
2058
- ### v0.2.3 — Context Combiner: merge 2+ related analyses into one combined spec
2059
-
2060
- ### v0.2.2 — Config: enforce per-key override-first resolution
2061
-
2062
- ### v0.2.1Move config editing into the `orc config` CLI (zero-token); drop `/orc-config`
2063
-
2064
- ### v0.2.0Doc-optional evidence-backed analyst + deep mode
1
+ # Changelog
2
+
3
+ All notable changes to ORC, newest first.
4
+
5
+ The **latest release** is also summarised in the [README](README.md#changelog).
6
+ This file is the full history, and it is the file `orc changelog` reads — that
7
+ command prints only the entries **newer than the version you have installed**.
8
+
9
+ Format: `### v<version> — <title> _(<date>)_`.
10
+
11
+ ---
12
+
13
+ ### v0.56.1 - a worker that is alive and doing nothing _(2026-08-28)_
14
+
15
+ **Still on the unscoped `orc` package?** Do this once before anything else -
16
+ your `orc upgrade` is the pre-v0.56.0 one and it cannot install itself:
17
+
18
+ - **Step 1 - release the command from the old package:** `npm uninstall -g orc`
19
+ - **Step 2 - install the current package:** `npm i -g @azure-id/orc`
20
+ - **Step 3 - re-apply it to your project:** `orc update`
21
+
22
+ **Do not use `npm i -g -f`.** Full detail in v0.56.0 below.
23
+
24
+ **An opencode dispatch that goes quiet mid-task used to burn the whole
25
+ fifteen-minute wall clock and then report `timeout`.** That word is a statement
26
+ about ORC's patience, and it reads as a budget somebody should raise. It was a
27
+ POSITION somebody should resume from - the thing you fix by hand by typing
28
+ `continue` into the worker's window.
29
+
30
+ A wall clock cannot tell a worker that is thinking hard from a worker that has
31
+ stopped. Both look like fifteen minutes of nothing.
32
+
33
+ - **`extra_stall_s` (default 180, `0` disables) is the fourth timeout, and the
34
+ only one that measures the WORKER rather than a socket.** It is reset by
35
+ observable progress in the three places progress can show up: new bytes on the
36
+ worker's stream, new bytes on its stderr, or a **declared file that changed on
37
+ disk**. That third signal is what stops it firing on a worker that thinks for
38
+ four minutes and then writes in one go. Engine `cli` only - engine `api`
39
+ already has a per-request inactivity timeout on its own socket.
40
+ - **Engine `cli` spawns ASYNCHRONOUSLY now, because `spawnSync` cannot be
41
+ watched.** It blocks the event loop for the whole dispatch, so nothing could
42
+ observe the child while it ran. The child's stdout still lands on the journal's
43
+ progress file, so the measurement is a `stat` and not a buffer in a parent that
44
+ might die. On Windows a `.cmd` shim is killed with `taskkill /T`, or the real
45
+ tool survives as a grandchild and edits the repository the next attempt is
46
+ about to resume into.
47
+ - **`stalled` is its own failure class and it is RETRYABLE.** That is the whole
48
+ point: `orc extra reconcile` reads the position out of the journal baseline and
49
+ `extra_resume` continues from what is already on disk instead of starting over.
50
+ **That is ORC's spelling of typing `continue`.** There is deliberately no key
51
+ that nudges the child on its stdin - `opencode run` is not an interactive
52
+ session, so a keystroke nobody reads would be a fake fix, and a fake fix looks
53
+ like the problem was handled.
54
+ - **Ordered once: stall < idle < api < wall.** A stall budget that cannot fit
55
+ under the wall clock stands down entirely and says why, rather than racing it -
56
+ two timers on the same instant report whichever won, which is the exact bug
57
+ `extraTimeouts` exists to prevent.
58
+ - **Every engine-`cli` return carries a `timeline`** - first byte, last progress,
59
+ longest quiet gap, and both budgets - on success as well as on failure. A
60
+ budget you can only see when it fires is a budget nobody can set before it
61
+ does. `first_byte_ms: null` is the honest reading of a worker that never said
62
+ anything, never `0`.
63
+
64
+ **`orc extra health <profile> [--model <id>]` - does this model stall?**
65
+ `0` answered - `1` stalled or failed - `2` unknown profile. It runs the live
66
+ probe through the SAME watchdog a dispatch uses, so a green badge is earned by
67
+ the path a wave actually runs. A **listed** model is not a **working** model, and
68
+ a working model is not a model that **finishes**: three different facts, and this
69
+ is the command that tells the third one apart.
70
+
71
+ **`extra_fallback_agent` (default `band`) - who picks the task up.** `band` is
72
+ the previous behaviour and stays the default, because a fallback that changes
73
+ tier is a re-plan nobody asked for. `ask` STOPS and puts the menu to you with the
74
+ failure and the position already on the table. Any installed agent name pins one.
75
+
76
+ - Under `ask` the lane does **not** choose: `fallback.agent` is `null` and the
77
+ trace line says `pending (extra_fallback_agent=ask)`. A lane that picked the
78
+ first option would answer the one question the setting exists to ask, and
79
+ `/orc-retro` would aggregate a decision nobody made.
80
+ - The menu is computed and the task's own agent leads it. The alternates are
81
+ `orc-executor-opus-5-med`, `orc-executor-opus-5-low` and
82
+ `orc-executor-sonnet-4-6-high`, and any installed agent name is accepted -
83
+ the roster is generated, so a closed list here would go stale.
84
+ - It changes WHO, never WHAT: the score does not move, `declared_files` is not
85
+ widened, `acceptance[]` is not touched. **INERT in `/orc-quick`**, announced at
86
+ the gate - re-opening that gate IS the ask.
87
+ - **A stop now NAMES the model.** The trace line read `profile/?` on a timeout,
88
+ and `orc extra stats` dedupes on the fields that line carries, so a stalled
89
+ dispatch could not be joined to a price, a provider, or another stall on a
90
+ different model.
91
+
92
+ ### v0.56.0 - a rename moved the command, and nobody could reach the fix _(2026-08-27)_
93
+
94
+ **READ THIS FIRST IF YOUR `orc upgrade` IS FAILING.** If you are on a version
95
+ before v0.56.0, this release cannot install itself - your `orc upgrade` is the
96
+ OLD one and it fails the same way every other route does. Run these three lines
97
+ once, by hand, and you are across for good:
98
+
99
+ - **Step 1 - release the command from the old package:** `npm uninstall -g orc`
100
+ - **Step 2 - install the current package:** `npm i -g @azure-id/orc`
101
+ - **Step 3 - re-apply it to your project:** `orc update` (add `--global` to also
102
+ refresh `~/.claude`)
103
+
104
+ Then check it worked: `orc version` should print 0.56.0 or newer, and
105
+ `orc doctor` should no longer mention `legacy-global-package`. Nothing in your
106
+ `.claude/` is touched by any of this, and your `orc.config.yaml` survives.
107
+ **Do not use `npm i -g -f`** - `--force` overwrites the command file and leaves
108
+ the old package installed underneath, owning nothing and never updated again.
109
+ From v0.56.0 onward `orc upgrade` does all three steps for you, announced.
110
+
111
+ **The package moved from the unscoped `orc` to `@azure-id/orc`, and every
112
+ upgrade path in the field died at once.** Both names declare the same `orc` bin.
113
+ npm links a bin only if the shim is unowned or owned by the installing package,
114
+ so with the old `orc` package still on disk globally, installing the new scoped
115
+ one failed with `EEXIST` on the command file itself. That error is about a FILE,
116
+ not a source - which is exactly why swapping sources changed nothing: the
117
+ tarball, the `github:` spec and the registry all failed identically, `orc
118
+ upgrade` walked all three and then printed npm's error wall, and `orc ui`'s
119
+ upgrade action did the same. `npm i -g -f` was the only thing that "worked", and
120
+ only by overwriting the command file and leaving the superseded package
121
+ installed underneath as a ghost that owns nothing and is never updated again.
122
+
123
+ - **The legacy package is EVICTED BEFORE any source is tried.** `orc upgrade`
124
+ now looks for a globally-installed package that is not this one and whose
125
+ `bin` declares `orc`, and uninstalls it first. Ordering is the point: the
126
+ collision fails every source identically, so walking the ladder first only
127
+ spends three network round trips arriving at the same `EEXIST`. It is
128
+ announced, never silent - it is a global npm mutation on the user's machine,
129
+ and the only one ORC makes for them.
130
+ - **Detection is by OWNERSHIP, never by directory name.** A directory called
131
+ `orc` that holds THIS package is not legacy, and a package that declares no
132
+ `orc` bin blocks nothing. A machine that never saw the rename land must not
133
+ have its working install uninstalled.
134
+ - **`--force` survives, scoped to the one case it is right for.** If a
135
+ collision remains after the eviction there was nothing to uninstall - an
136
+ ORPHANED shim npm left behind with no package owning it. `--force` overwrites
137
+ a file that belongs to nobody, which is the case it exists for.
138
+ `isBinShimCollision` requires the `EEXIST` code AND a path component that IS
139
+ the bin name, so it never reaches for `--force` on an unrelated `EEXIST`
140
+ deeper in a dependency tree.
141
+ - **The npm REGISTRY is now tried first**, then the tarball, then the `github:`
142
+ spec. The registry resolves a VERSION rather than a branch tip; the `github:`
143
+ spec shells out to git and fails under restricted git / NVM, so it stays last.
144
+ `--from` and `ORC_INSTALL_SPEC` still win outright, and the remembered
145
+ `last_good_spec` still leads.
146
+ - **`freshCliPath()` resolves the SCOPED directory first.** It looked only under
147
+ `<npm root -g>/orc`, which after the rename is the LEGACY package - so on a
148
+ machine mid-rename it resolved a path that existed and step 2 re-applied the
149
+ very templates step 1 had just superseded. A hit is now accepted only if the
150
+ manifest there says the current package name: a directory that exists is not
151
+ proof of identity.
152
+ - **`orc doctor` reports it by name.** `legacy-global-package` is the one
153
+ finding that explains why `orc upgrade` cannot fix anything else in the
154
+ report. It is deliberately NOT `--fix`-able: `orc doctor --fix` is scoped to
155
+ this project's `.claude/`, and evicting a global npm package is neither
156
+ project-scoped nor something to do without saying so - so its `fix_command`
157
+ points at `orc upgrade`, which does it announced. `FINDING_ROUTE` sends it to
158
+ Maintenance, where the upgrade action is.
159
+ - **A CAUTION at the top of the README carries the one-time manual fix**, because
160
+ the fix cannot reach the people who need it most: a user still on the old
161
+ package does not have this code, so their `orc upgrade` still fails. Two lines
162
+ (`npm uninstall -g orc` then `npm i -g @azure-id/orc`) get them across once,
163
+ and from here `orc upgrade` handles it.
164
+
165
+ ---
166
+
167
+ ### v0.55.2 - a gate that is never probed is a gate that is always off _(2026-08-27)_
168
+
169
+ **`/orc-quick` and `/orc-fast` documented the foreign-worker option and then
170
+ never went and looked for it.** Both lanes carried the full `orc extra` slot
171
+ contract - the menu line, the dispatch call, the failure path - but neither
172
+ preflight ever RAN the probe that answers whether a position is held. orc-quick's
173
+ Q0 said "read `log_dir` only, read no other key"; orc-fast's F0 had gates a, b
174
+ and c and no extra step, while the F2 prose claimed the `extra:` line "joins the
175
+ F0 preflight". So a user who armed `extra_enabled` and set
176
+ `orc extra role set quick-executor ds/deepseek-chat` was still offered the two
177
+ shipped Claude executors and nothing else, with no way to tell configuration
178
+ from a bug.
179
+
180
+ - **orc-quick Q0 gains one PROBE**, named as the single exception to
181
+ "read no other key": `orc extra resolve --slot quick-executor --json`. One
182
+ command answers the master gate, the position and the routing together, so the
183
+ code-writing menu can render line 3. It is still an OPTION - never a default,
184
+ never sticky, re-asked after a failure.
185
+ - **orc-fast F0 gains gate `d`**, a probe rather than a gate:
186
+ `orc extra resolve --slot fast-executor --json`. Resolved `extra` prints the
187
+ P0 `extra:` line where the prose always said it would, naming the agent it
188
+ displaces (`orc-executor-sonnet-4-6-high`); resolved `claude` prints nothing
189
+ and never falls back - no row on a slot is an ANSWER, not a gap.
190
+ - **`/orc-doc` was never affected.** Its targets are resolved by
191
+ `docExtraResolve` inside `orc doc next`, so the CLI computes them and no
192
+ preflight step can forget to ask. That is the shape the other two now borrow.
193
+
194
+ No CLI change, no config key, no agent change.
195
+
196
+ ### v0.55.1 ORC is on npm _(2026-08-27)_
197
+
198
+ **ORC is published as [`@azure-id/orc`](https://www.npmjs.com/package/@azure-id/orc).**
199
+ The GitHub tarball still works and nothing about the payload changed — no skill,
200
+ no agent, no CLI behaviour moved. This is the install path getting a name.
201
+
202
+ - **`npm i -g @azure-id/orc`** is the install, and
203
+ **`npm i -g @azure-id/orc@latest`** is the update. `orc upgrade` already
204
+ fetched the newest package and then applied it, and it continues to;
205
+ `orc upgrade --from @azure-id/orc` names npm explicitly.
206
+ - **The GitHub tarball is the fallback now**, not the headline kept in the
207
+ Quick start behind a fold for forks and for anyone pinning a branch.
208
+ - **`orc update` is unchanged**: it re-copies the package you already have and
209
+ never touches the network, so `npm i -g @azure-id/orc@latest && orc update`
210
+ is the manual spelling of `orc upgrade`.
211
+
212
+ ---
213
+
214
+ ### v0.55.0 — a score is what a band needs, and four lanes do not have one _(2026-08-26)_
215
+
216
+ **A score is what a band needs, and four lanes do not have one.** `/orc-quick`,
217
+ `/orc-fast`, `/orc-doc` and `/orc-wiki` pin an agent to a POSITION rather than
218
+ scoring a task. `orc extra` routed them anyway by resolving the pinned agent's
219
+ score band at both edges, which is arithmetic on a number nobody chose.
220
+
221
+ It was wrong twice and dead once. A document set to `checker` resolved the
222
+ **writer's** band for a role it was not routing. `/orc-wiki` asked for a role
223
+ named `scanner` that `extra_roles` refuses by name, so that lane could never
224
+ route however it was configured `orc extra lanes` printed `claude` forever,
225
+ with a reason that read like a user's choice. And `orc extra dispatch` required a
226
+ `score` unconditionally, so **no non-scored dispatch had ever reached the bridge
227
+ at all** not the fence, not the journal, not the spend log.
228
+
229
+ - **`orc extra role` holds six POSITIONS**: `quick-executor` · `fast-executor` ·
230
+ `doc-writer` · `doc-checker` · `wiki-scanner-deep` · `wiki-scanner-light`. One
231
+ named position, one chosen `profile/model`, and **a row's presence is the
232
+ arming**. `list` prints all six always an unrouted position keeps its slot
233
+ and reads as the Claude agent it falls through to, because "I left the checker
234
+ on Claude on purpose" and "there is no checker" must never look the same.
235
+ - **A second resolver that never touches a band.** `orc extra resolve --slot
236
+ <slot>` is the sibling of the score shape, same answer, same exit codes, and
237
+ the Claude answer it carries is a **pinned NAME rather than an interval** —
238
+ strictly more honest than what the scored half can offer. Nine hold-backs, each
239
+ answered by name; a cited risk is never invented for a lane that has none.
240
+ - **Precedence, one sentence for both shapes:** extra decides *whether* a Claude
241
+ agent runs at all; `opus5_only` and the score tables only decide *which* Claude
242
+ agent runs where extra did not take it. Under a taken slot `opus5_only` is **not
243
+ consulted** — and it stays fully live for every position with no row. `orc
244
+ config list` and `orc config set` now name the taken POSITIONS beside the taken
245
+ bands.
246
+ - **The bridge accepts a slot.** Exactly one of `score` or `slot`; both is
247
+ refused by name; `band` becomes `slot:<slot>` so the trace parser, the
248
+ eight-field dedupe and `orc extra stats` are untouched and each position gets
249
+ its own cost row for free. **Zero new engines, zero new dispatch paths, zero new
250
+ agents** the fence, the cap, the credential triangle, the journal, the spend
251
+ log and the resume ladder all come along unchanged.
252
+ - **Per lane:** `/orc-doc` resolves each role against its OWN slot and `orc doc
253
+ next` names the model per role before the wave (a document's voice is the
254
+ deliverable); `/orc-wiki` prints its target beside the tier it already prints;
255
+ `/orc-fast` names the agent it displaced in the F0 line; **`/orc-quick` gets a
256
+ THIRD OPTION on its menu** — never a default, never sticky, re-asked after a
257
+ failure, because that gate's whole premise is asking.
258
+ - **`orc ui ▸ Extra ▸ Routing` grows a second ladder** below the bands, and
259
+ **zero config keys were added** a second master gate, per-lane switches,
260
+ `extra_quick_ask` and a per-slot model key were all considered and are written
261
+ down as refused.
262
+
263
+ ---
264
+
265
+ ### v0.54.0 — a failed dispatch is a POSITION, not a blank page _(2026-08-25)_
266
+
267
+ **A worker on another model wrote six of seven lines and lost its connection.
268
+ ORC sent the same task to Claude from scratch — onto a file that was already
269
+ two-thirds written.**
270
+
271
+ `orc extra` had exactly one recovery move: re-dispatch the SAME slice to the
272
+ Claude band. That move assumes the worktree is where the dispatch found it. **It
273
+ usually is not.** The replacement executor's three plausible moves were all
274
+ wrong: `Write` the file whole and discard work you already paid for · `Edit`
275
+ against a stale mental model so `old_string` does not match and it improvises ·
276
+ read first and then guess whether what is there is its own earlier work, a
277
+ teammate's, or garbage. No field in the slice could have told it, and no field in
278
+ the return contract could have carried it.
279
+
280
+ **The registered token, sixth in its family:** `a lane that re-does work the
281
+ worktree already contains` has broken this contract. It joins `a lane that
282
+ answers its own interview question`, `a lane that picks its own favourite`, `a
283
+ lane that fixes what it judged`, `a lane that picks its own council`, `a lane
284
+ that reads its own document`, and `a lane that sends work off Claude without
285
+ saying so`.
286
+
287
+ - **THE JOURNAL IS THE CLI'S, AND IT IS WRITTEN BEFORE THE FIRST BYTE LEAVES THE
288
+ MACHINE.** `.claude/orc/extra-journal/<task_id>/` a header carrying HEAD,
289
+ `git status --short` in full and a hash plus a line count for every
290
+ `declared_files` entry; a progress log appended as the dispatch runs; a result
291
+ written beside the spend append. It is written by `orc extra dispatch` itself,
292
+ which is the **fourth** time this repo has chosen a written-by-the-CLI fact
293
+ over a relayed one (v0.32.0 narration, v0.49.5's hand-back page, v0.53.2's
294
+ spend log). No lane writes it, no lane can forget it, and it is best effort by
295
+ construction: a journal that cannot be written never takes the dispatch down.
296
+ The header is the only record of what the repository looked like before a
297
+ third party touched it, which is the only thing that makes a reconciliation
298
+ possible at all.
299
+ - **`orc extra reconcile <task_id>` FREE, deterministic, and it runs before
300
+ anything paid.** Five states, five exit codes (0 `resumable` · 1
301
+ `nothing-to-resume` · 2 `no-journal` · 3 `complete` · 4 `in-flight`), and 0 is
302
+ the answer the command exists to give rather than "healthy". Per declared file:
303
+ `untouched` · `created` · `modified` · `deleted` · `reverted`, with line counts
304
+ where they can be computed EXACTLY and `null` where they cannot — **unknown is
305
+ not zero**. Plus `touched_undeclared[]` (a fence breach, surfaced here because
306
+ a crashed dispatch is exactly when the worktree delta never ran), the last
307
+ recorded action, and the partial token vector.
308
+ - **It deliberately does NOT decide whether a file is finished.** No brace
309
+ counter, no truncation heuristic, no language sniffing /orc-doc's house-rule
310
+ boundary verbatim: the CLI cannot parse intent, so it does not pretend to, and
311
+ **a fake validator would be worse than none.** The checks that answer "is this
312
+ done" already exist and are already engine-blind. Reconciliation's job is to
313
+ point them at the right thing.
314
+ - **ATTRIBUTION whose fault it was, with the evidence.** Five verdicts, each
315
+ carrying a different correct recovery: `provider` · `network` · `local` ·
316
+ `worker` · `orc`. **`network` HOLDS THE WAVE** a Claude fallback cannot
317
+ succeed when the machine has no network, so falling back would be a second
318
+ failure and a second cost for nothing. The two are told apart by ONE
319
+ unauthenticated 3-second request on a path that has already failed, made only
320
+ on the reasons that cannot be separated without it. `orc` is on the list on
321
+ purpose: a report about a third party with no way to blame its own author is
322
+ not a report anybody should trust v0.53.3 was exactly an ORC bug that
323
+ presented as a bad key.
324
+ - **`orc extra resume-slice <task_id> --out <f>` composes the continuation, and
325
+ the CLI owns the wording.** It is a NEW DISPATCH OF A DERIVED SLICE through the
326
+ ordinary bridge zero new engines, zero new dispatch paths, **zero new
327
+ agents** so the fence, the concurrency cap, the credential rules, the spend
328
+ log and the worktree delta all come along unchanged. It **never widens
329
+ `declared_files`**, **never moves `acceptance[]`**, **never moves the score**
330
+ (a resume is not a discount), and **refuses on a drifted slice**, naming both
331
+ hashes.
332
+ - **Where a resume goes is DERIVED, never a config key.** Retryable → the same
333
+ profile in a new session, up to `extra_resume_max`. Non-retryable the Claude
334
+ band, **still as a RESUME slice** which is what fixes the original bug: the
335
+ Claude fallback stops being a from-scratch dispatch, which it should never have
336
+ been. A key here would let somebody configure "always the same profile" and
337
+ then wait out the cap × a 401.
338
+ - **Six refusals, each NAMED, each writing NOTHING** (`not-resumable` ·
339
+ `in-flight` · `reverted-file` · `slice-drifted` · `resume-cap` ·
340
+ `resume-disabled`). **A live attempt is never resumed:** a dropped socket does
341
+ not prove a provider stopped streaming, so a resume is gated on the pid being
342
+ gone OR the lease having expired — and past the lease a live pid is treated as
343
+ somebody else's process, stated as the honest bound it is rather than as proof.
344
+ **A `reverted` declared file blocks and names the paths:** resuming on top of a
345
+ possible destructive action is the one case where continuing is worse than
346
+ starting over, and ORC does not get to make that call.
347
+ - **Two new failure classes make the recovery choosable.** `stream-interrupted`
348
+ (the connection was established and then died `unreachable` means it never
349
+ opened, and those two want opposite recoveries) and `connection-lost-local`
350
+ (the same, with the probe also failing). A taxonomy that returned one word for
351
+ both could not pick either, which is why there was only ever one recovery.
352
+ - **JOURNAL FIDELITY IS DECLARED PER ENGINE and never rendered stronger than it
353
+ is.** `api` and `claude-shim` are `per-turn`; engine `cli` is
354
+ `streamed-opaque`its child's stdout now goes to a FILE DESCRIPTOR rather
355
+ than a buffer in a parent that dies, so a wall-clock kill leaves the bytes on
356
+ disk and `output_file` stops being `null`. ORC captured them and did not
357
+ interpret them, and **a gap that is not reported reads as a capability**.
358
+ - **A killed dispatch's spend is recoverable.** `appendExtraSpend` runs after the
359
+ engine returns, so a killed parent left real money invisible to every cost
360
+ report the v0.53.2 hole through a different door. Reconcile writes the
361
+ journal's running vector once, idempotently, as `recovered: true, complete:
362
+ false`. **Measured is not unknown; unknown is not zero; a recovered vector is a
363
+ FLOOR and says so.**
364
+ - **Orphans are REPORTED at preflight and never resumed.** `orc extra preflight`
365
+ lists every journal with a header, no result and an expired lease and does
366
+ **not** change its exit code, because an orphan is a finding, not a stop.
367
+ Silently continuing a third party's half-finished write into somebody's
368
+ repository is the same class of act as routing off Claude without saying so.
369
+ - **Reliability becomes a MEASURED property of a profile.** `orc extra stats`
370
+ gains per-profile `dispatches` · `failed` · `resumed` · `orphaned` · mean time
371
+ to failure · the attribution split, and **below 10 dispatches there is no rate
372
+ at all** a percentage from three tries is noise with a percent sign on it.
373
+ `orc extra doctor` gains `extra-orphan-dispatch` and `extra-profile-unreliable`
374
+ (never below the floor). Both ABSENT counts are named.
375
+ - **`orc ui ▸ Extra ▸ Recovery`** — a sixth tab, not a tenth card. One row per
376
+ journal, **expanded in place** (the Runs-row rule), and the free/paid line is
377
+ visible: `reconcile` is a button, `resume-slice` is a copy-able command,
378
+ because the panel never runs a lane. A row with nothing to show KEEPS ITS SLOT;
379
+ `in-flight` renders as a refusal with its reason; prune is preview-then-apply
380
+ and **names every directory**. Spending gains the reliability strip. Overview
381
+ gets one line, only when there is something to say, and it never offers to
382
+ continue anything.
383
+ - **Two new config keys, and the four that were refused are written down.**
384
+ `extra_resume` (`on`) and `extra_resume_max` (`2`) — nine keys became eleven.
385
+ Deliberately NOT added: a key for where a resume goes, a key for the retry
386
+ ladder (`extra_timeout_s` is already the budget), a key to disable the journal
387
+ or its 30-day retention (**a record you can switch off is off on the run you
388
+ needed it for**), and a key for the network probe. `extra_resume` is INERT in
389
+ `/orc-quick`, announced at the agent gate.
390
+ - **New trace verbs** `EXTRA resume` and `EXTRA orphan`, composed by the CLI and
391
+ copied verbatim a resume that leaves no line cannot be counted by
392
+ `orc extra stats` or `/orc-retro`. New mocked run: `mock-run/extra-recovery.md`.
393
+
394
+ ---
395
+
396
+ ### v0.53.4 the reload that dropped its own token _(2026-08-24)_
397
+
398
+ **Every `orc update` from the panel ended on `This link is missing its session
399
+ token.` and the token was never missing.**
400
+
401
+ v0.53.2 taught the server to hand itself over to a fresh process on the SAME
402
+ port and the SAME token, so the URL in the address bar stays valid and the open
403
+ tab only has to reload. That half worked. The reload did not: the panel strips
404
+ `?t=` out of the visible URL at boot (`00-core.js`, so the token never lands in
405
+ a screenshot or a pasted link), and the hand-over then called
406
+ `location.reload()` which re-requests **the stripped address**. No `?t=`, no
407
+ `x-orc-token` header on a document request, and the server correctly answered
408
+ with the un-authenticated page. Deterministic, on every maintenance action that
409
+ declares `restarts_ui`.
410
+
411
+ - **A reload is not `location.reload()` here.** `reloadWithToken()` re-attaches
412
+ the in-memory token and `location.replace()`s that URL. It is the only reload
413
+ route in the panel, and a test fails on any bare `location.reload()` in
414
+ `app.js` the stripping is deliberate, so the fix has to be the reload, not
415
+ the strip.
416
+ - Nothing about the server, the successor, the lock, the token generation or the
417
+ `restarts_ui` declaration changed. The upgrade had already installed by the
418
+ time the page broke; the user's recovery — `orc ui --stop` then `orc ui` — was
419
+ producing a *new* token for a server that was already the new build.
420
+
421
+ ---
422
+
423
+ ### v0.53.3 the key it never sent _(2026-08-24)_
424
+
425
+ **A vaulted, verified, routed connection authenticated every wave with the wrong
426
+ secret, and four separate green checks agreed it was fine.**
427
+
428
+ `orc extra dispatch` resolved the credential by passing `inMemory:
429
+ process.env.ORC_EXTRA_KEY` into `extraCredentialValue`, and that option
430
+ short-circuited the vault branch **on its first line**. So whenever
431
+ `ORC_EXTRA_KEY` was set in the environment a leftover from another profile,
432
+ another provider, another day dispatch sent *that* value and never opened the
433
+ vault at all. The profile's real, verified, vaulted key was never consulted.
434
+
435
+ Only `dispatch` and `conform` passed that option. `ping`, `models --test` and
436
+ `preflight` all resolved without it, opened the vault, and succeeded. Hence the
437
+ part that made this expensive to find:
438
+
439
+ ```
440
+ orc extra doctor → nothing to report.
441
+ orc extra list → dipkshit deepseek/api verified key vault
442
+ orc extra preflight → dipkshit ✔ ok saved until 2027-08-19
443
+ orc extra models dipkshit --test <model> → answered in 1866ms
444
+ ```
445
+
446
+ Four checks, each honest about the path it exercised, **none of them exercising
447
+ the path a dispatch takes**. Then the wave died at HTTP 401
448
+ `Your api key: ****w5f7 is invalid` — pointing at the vaulted key the user had
449
+ verified four minutes earlier, while the key ORC actually sent came from an
450
+ environment variable the message never named. Nothing was written and nothing was
451
+ billed; the run halted at F2 under `extra_on_failure: stop`.
452
+
453
+ - **The two in-memory options were one option, and they are different facts.**
454
+ `opts.inMemory` is an **explicit** key supplied for this invocation
455
+ (`--key-stdin`) — the key being tested and then stored, so it still wins.
456
+ `opts.ambientKey` is a key found lying in the environment, and it is now what
457
+ it was always written to be: the **unattended-wave fallback**, applying only to
458
+ a vault that cannot be opened here (`extra_unlock: per-dispatch`, where nothing
459
+ is cached on purpose). **A vault ORC can open always wins.**
460
+ - **A passphrase in hand that the vault refuses is a real answer about the
461
+ declared source,** not a reason to reach for a leftover variable. It returns the
462
+ refusal rather than burning an attempt and then sending the wrong secret anyway.
463
+ - **The return now reports the source it USED.** `credential.source` is one of
464
+ `vault` · `env` · `ambient` · `memory` · `tool`, and it describes what happened
465
+ rather than what the profile declares the two disagreed for a release, so the
466
+ one field that could have named the bug confirmed the wrong story instead.
467
+ `credential_override` is printed whenever the profile's declared source was not
468
+ the one used, pass or fail: an override nobody was told about is the same class
469
+ of silence as work leaving Claude with no `extra:` line.
470
+ - **A 401 names the source that produced the rejected secret.** The provider's
471
+ message describes what it saw; only ORC knows where that came from. It was a
472
+ five-minute fix and a multi-step diagnosis.
473
+
474
+ **`ORC_EXTRA_KEY` holds the KEY, and `orc extra keyhelp` said it was the
475
+ passphrase.** For a vaulted profile it rendered a per-OS instruction to export
476
+ `ORC_EXTRA_KEY="<your passphrase>"`into the exact variable a dispatch sends to
477
+ the provider in an `Authorization` header. Following ORC's own instruction handed
478
+ the secret that opens the vault to a third party. The block is gone. In its place
479
+ the route **with a deadline on it** renders first (`orc extra session <name>
480
+ --save --ttl 30`, the v0.52.0 design), then the variable, described as the key,
481
+ with the warning that a passphrase must never go there. Nothing in ORC reads a
482
+ passphrase from the environment, so `passphrase_env` is now always `null`.
483
+
484
+ **One completions URL, and the probes speak it.** `ping` rung 2 and
485
+ `models --test` hardcoded `{base}/chat/completions` while dispatch derived
486
+ `{base}/v1/chat/completions` through `apiCompletionsUrl` and neither probe
487
+ honoured a profile's `completions_path` at all. DeepSeek accepts both spellings,
488
+ so this was not the 401; on a provider that accepts only one it produces a
489
+ profile that verifies **green** and dispatches into a 404, which is the same lie
490
+ wearing a different status code. Both probes now call the same builder.
491
+
492
+ **And the unknown-model escape has to be about the model.** A 400/404/422 on the
493
+ probe's invented model id was read as proof that the endpoint authenticated
494
+ before declining the name which is only true if the endpoint is the one it was
495
+ aiming at. A gateway answering `Unknown request URL` with a 404 authenticated
496
+ nothing. The rejection must now name the model asked for, or say something about
497
+ a model/engine/deployment; otherwise the ping fails honestly instead of
498
+ verifying. `verify_credential_source` records which credential earned the badge.
499
+
500
+ **The fake provider was more permissive than the provider.** It answered a
501
+ completion on **any** path, which is precisely why two probes could hardcode the
502
+ wrong one for three releases with a green suite. It now serves exactly the path
503
+ `apiCompletionsUrl` derives and 404s the rest — the v0.53.0 rule, applied to the
504
+ third surface in a row that broke on it.
505
+
506
+ ---
507
+
508
+ ### v0.53.2 the cost that was paid and never written down _(2026-08-24)_
509
+
510
+ **Two foreign dispatches ran, cost real money, and every cost report read zero.**
511
+
512
+ `orc extra dispatch` composes an `EXTRA …` trace line and hands it back for the
513
+ lane to copy into a phase packet. That is a RELAY THROUGH A MODEL — the
514
+ remembered-not-dispatched pattern this repo has already lost to twice and it
515
+ broke in both directions on two graded runs of the same feature:
516
+
517
+ - one wrote `EXTRA Codex/gpt-5.4-mini :: engine=cli …`, adding the trace's own
518
+ `verb :: tail` separator, which the parser did not accept;
519
+ - one dropped the line entirely and folded the token vector into a free-form
520
+ `VERIFY` sentence.
521
+
522
+ Both dispatches SUCCEEDED. `return.json` and `return-fast.json` were sitting in
523
+ the run folder with complete four-kind vectors 27,029 / 0 / 159,616 / 1,895 for
524
+ codex, 136 / 0 / 20,032 / 134 for opencode and a perfectly formed `trace_line`
525
+ inside each. `orc extra stats` reported **0 dispatches from 2 traces**, `orc extra
526
+ rates` had no pair to price, and `orc ui Extra Spending` read **`0 tasks
527
+ sent`**. A cost report that reads zero when money was spent is worse than no
528
+ report, because a zero gets believed.
529
+
530
+ - **THE BRIDGE WRITES THE SPEND DOWN ITSELF.** Every dispatch appends one JSON
531
+ object to `.claude/orc/extra-spend.jsonl` at the moment it holds the numbers —
532
+ profile, provider, model, engine, task, band, the four token kinds unblended,
533
+ outcome, duration, the run it belonged to, and the `trace_line` it composed.
534
+ The `RESUME.md` lesson from v0.49.5 applied to money: **the fact is recorded by
535
+ the hand that computed it.** Best effort by construction — a record that cannot
536
+ be written never takes a dispatch down and the dispatch says `spend_logged`
537
+ either way, because a dispatch no cost report can see is worth one line now
538
+ rather than a mystery later.
539
+ - **The trace line is NOT retired, it is DEMOTED to the second source.** It is
540
+ still the run's narrative and still what `/orc-retro` reads; it is no longer
541
+ what the money depends on. The two are DEDUPED on the eight fields the line
542
+ itself carries, so a lane that relays correctly is counted exactly once —
543
+ double-counting a correct relay would punish the behaviour the contract asks
544
+ for.
545
+ - **The parser now accepts the ` :: ` a trace writer reaches for by reflex.**
546
+ Every other verb in a trace is `VERB … :: tail`. A line that is faithful about
547
+ the numbers and off by two characters in its punctuation must still parse.
548
+ Tolerance is a net under the contract, not a licence to reshape the line.
549
+ - **A saved dispatch return backfills a run made before any of this existed.**
550
+ `{run_dir}/<slug>/*.json` is read as a THIRD source when — and only when — it
551
+ carries `dispatched: true` and a `trace_line` this parser accepts. That is the
552
+ CLI's own payload read back, not a narrative about it, which is what separates
553
+ a recovery from an invention. It carries no date and **none is derived from an
554
+ mtime** (the `/orc-pact` UNCHECKABLE rule), so `--since` excludes those rows and
555
+ says how many.
556
+ - **Every count says which source it came from,** on both surfaces. "ORC wrote
557
+ this down itself" and "a trace happened to mention it" are different levels of
558
+ confidence in the same total. Two ABSENT counts are named rather than absorbed:
559
+ a torn log line, and an undated saved return a date filter dropped — a report
560
+ that is quietly short by three rows is the exact failure being fixed.
561
+
562
+ **And the panel now survives its own upgrade.**
563
+
564
+ `orc upgrade` replaces the package the running `orc ui` server was loaded from.
565
+ Node read `bin/webui` at require time and `STATIC` is a one-time walk at boot, so
566
+ an upgraded panel keeps serving the old bytes: the version in the rail does not
567
+ move, a new panel does not appear, and a fixed bug is still there. The remedy was
568
+ three manual steps nobody was told about stop the server, re-run `orc ui`, open
569
+ the new URL.
570
+
571
+ - **The server hands itself over.** After a maintenance action DECLARED as
572
+ replacing the install (`update`, `prune`, `fix`, `upgrade` never
573
+ `update-global`, which targets `~/.claude`) succeeds, the panel restarts on the
574
+ **same port and the same token** and the open tab reloads itself. A successor on
575
+ a new address is not a restart; it is a second server, and the tab you are
576
+ looking at would still point at the corpse.
577
+ - **CLIENT-TRIGGERED, never automatic on the job's close handler.** The job's
578
+ output lives in the server's memory, so restarting the instant a command
579
+ finished would destroy the record of what it did before anyone read it. It also
580
+ means a tab that is already closed leaves the old process running, which is the
581
+ safe resting state.
582
+ - **The token travels in the ENVIRONMENT, never in argv** it authenticates a
583
+ write surface, which puts it in the same class as the credentials `orc extra`
584
+ refuses on a command line. It is read once at boot and deleted from
585
+ `process.env`, so no CLI subprocess the server shells out to inherits it.
586
+ - **A failed handover is a note and two commands, never a broken page.** The old
587
+ panel keeps working; it just prints `orc ui --stop` and `orc ui`. And the
588
+ confirmation says the restart is coming BEFORE the applya panel that reloads
589
+ itself with no warning reads as a crash.
590
+
591
+ ---
592
+
593
+ ### v0.53.1"up to date" now names what it checked _(2026-08-23)_
594
+
595
+ **A one-line diagnostic for the update check that could not be questioned.**
596
+
597
+ The update check was never broken, and that was the problem. `orc version` reads
598
+ `package.json` from `UPDATE_URL`; `orc upgrade` installs from `TARBALL_SPEC`.
599
+ They are two different URLs on what is *normally* the same branch — and only the
600
+ second one was ever printed, on either surface. The Maintenance panel's `source`
601
+ row shows the install tarball, so a reader concludes the version comparison read
602
+ main too.
603
+
604
+ That gap makes a true statement unfalsifiable. A maintainer who cut v0.53.0 on an
605
+ unmerged release branch saw `✓ up to date` against a main that was still at
606
+ 0.52.0, with nothing on screen to distinguish "you are current" from "the release
607
+ never reached the ref this reads". There is no way to tell those apart from the
608
+ output, which is why it reads as a defect in the checker.
609
+
610
+ So the number and the ref it came from now travel together, everywhere the number
611
+ is reported:
612
+
613
+ - **`orc version`** prints `✓ up to date (azure-id/orc@main is at 0.52.0)`, and
614
+ the offline branch names the unreachable ref rather than saying "source".
615
+ - **`orc version --json`** gains `checked_source` (the URL) and `checked_ref` (the
616
+ `owner/repo@ref` label). This is not a new idea: `orc changelog --json` has
617
+ always carried its own `source`, and this is that field's missing twin a
618
+ field the human path implied and the JSON omitted.
619
+ - **`orc ui` ▸ Maintenance** gains a `version read from` row beside `source`, so
620
+ the two URLs are visibly two URLs. The fixture carries both fields.
621
+
622
+ `checkSourceLabel()` shortens a `raw.githubusercontent.com` URL to
623
+ `owner/repo@ref` and returns anything else verbatim a custom `ORC_VERSION_URL`
624
+ is shown as written rather than mangled into a label that does not describe it.
625
+
626
+ **Nothing about the check itself changed.** No new request, no new cache, no
627
+ change to the 24h TTL, `ORC_NO_UPDATE_CHECK` or the comparison. The only thing
628
+ that is new is that the answer can now be checked.
629
+
630
+ ### v0.53.0 the schema the provider rejected, and a routing table you can read _(2026-08-23)_
631
+
632
+ **One outage, one defect visible at a glance, and the Extra panel rebuilt.**
633
+
634
+ **The outage.** Engine `cli` on **codex** had been 100% dead for a release, and
635
+ the suite was green the whole time. ORC handed codex an `--output-schema` with
636
+ `additionalProperties: true`; OpenAI structured outputs require a **closed**
637
+ object at every level, so every dispatch was an **HTTP 400 raised before the
638
+ model was ever reached** fast, free, and reported as something vague. Flipping
639
+ only that flag is a **second** 400, this time naming `files_changed`, because
640
+ `required` must list every key in `properties`. An optional field is a nullable
641
+ union now, never an omission from `required`, and the shape is documented as
642
+ **provider-dictated rather than chosen** the comment calling it "deliberately
643
+ minimal" is what produced the bug.
644
+
645
+ Three things went with it:
646
+
647
+ - **The classifier was reading the wrong stream.** codex relays the upstream
648
+ `invalid_request_error` inside its own event stream on stdout while printing a
649
+ benign notice on stderr, so a precisely-diagnosable, non-retryable failure came
650
+ back as `unknown` and `retry: false` was reached by luck. The codex adapter
651
+ now classifies from **the provider's own error object** first, and
652
+ `classified_from` says which of the two answered a field that reports where
653
+ a verdict came from must not lie about it.
654
+ - **A measurement was being reported as unknown.** codex *does* report
655
+ `cache_write_input_tokens`; the adapter declared three usage kinds, so ORC
656
+ threw a real number away and then said it was never measured.
657
+ `reasoning_output_tokens` is still deliberately unread the Responses API
658
+ counts it inside `output_tokens`, and an unproven pricing change is worse than
659
+ a missing one.
660
+ - **And the reason it shipped green: the fake was more permissive than the
661
+ provider.** It asserted the schema existed and mentioned `status`, and modelled
662
+ none of OpenAI's rules. That is the **third release in a row** broken by the
663
+ same shape `--auto` renamed, a greedy `-f` array, now an open schema. **A
664
+ strict third-party parser fails for free, and it looks like a model problem.**
665
+ The defence is the same every time: the fake must be at least as strict as the
666
+ real thing. It now rejects both 400s by name.
667
+
668
+ **The ellipse.** A ready-and-verified tool card drew its "connected as" chip as a
669
+ 250px green ellipse. `.ex-tool` declared `grid-template-rows: auto auto auto 1fr
670
+ auto` but **four states carry four different numbers of children**, so the chip
671
+ landed in the `1fr` slack row, stretched (a grid item's default), and a 999px
672
+ radius did the rest. It hit whichever ready card had the shortest content in its
673
+ row, so it was never about one tool. The card is a flex column now, with no row
674
+ template at all. The old test asserted the property was *present* — which it was,
675
+ while the panel drew an ellipse.
676
+
677
+ **The Extra panel.** It was nine cards in one 8,786px scroll: no first step, no
678
+ last step, no way to be *done* with a section.
679
+
680
+ - **Five tabs** on the panel's own precedent Setup, Routing, Limits, Spending,
681
+ Providers. The header strip and "what needs your attention" stay outside them,
682
+ because a caution you have to go looking for is a caution nobody reads. The
683
+ open tab survives a re-render, and the gate still decides what **exists**: with
684
+ nothing connected, three tabs are not rendered as empty shells.
685
+ - **One vertical band ladder** replaces the horizontal rail *and* the duplicate
686
+ list of rows below it. The target is no longer truncated, the widths no longer
687
+ lie (a `min-width` floor was fighting the percentage), nothing is off-screen,
688
+ there is a **legend**green means the work leaves your machine and the row
689
+ you read is the row you edit.
690
+ - **The plain-language range is the CLI's.** `orc extra route` gains `range`
691
+ ("scores 0 to 29") and `meaning` per row, printed on the human path as well.
692
+ Writing "simple work" beside a score in the panel would be the panel deciding
693
+ what a score means.
694
+ - **One sentence and one control per tool state**, with the diagnostics behind a
695
+ disclosure.
696
+ - **Wording**: the panel was serving **design rationale as user instruction**.
697
+ Six keys split the instruction first, in Simplified Technical English, the
698
+ reasoning collapsed underneath. Nothing deleted, both languages, and the
699
+ rationale keeps its voice.
700
+
701
+ Setup per provider: **[`guides/extra-models.md`](guides/extra-models.md)**.
702
+
703
+ ---
704
+
705
+ ### v0.52.0 — the connection that could not be used, and the routing nobody could see _(2026-08-23)_
706
+
707
+ **Eleven defects, one release.** Five came out of a real `/orc-fast` run against
708
+ a verified, routed local tool a run that fell back to Claude twice over, for
709
+ two unrelated reasons, neither of which was the model. Six more came out of
710
+ reading the panel afterwards, and they are one theme with several faces:
711
+ **Extra was invisible to every surface that is not the Extra panel.**
712
+
713
+ **The two that killed that run.**
714
+
715
+ - **`opencode` dispatch was dead on arrival.** `-f` is a yargs **array** flag,
716
+ and a yargs array is **greedy**: every non-flag token after it is swallowed as
717
+ another file path. ORC pushed the message last, so `message..` arrived empty
718
+ and opencode exited 1 in its own parser `dur=0m01s`, `tok=none`,
719
+ `outcome=failed`, looking exactly like a model problem. Engine `cli` on that
720
+ tool was 100% dead for a release. The message comes first now, `-f` comes
721
+ last where it has nothing left to eat, and the test fixture asserts **that a
722
+ message arrived** rather than that a flag was present.
723
+ - **A tool that signs itself in was being forced into the vault.** `--tool-auth`
724
+ has existed in the CLI since v0.51.0 and the panel offered two radios, so a
725
+ connection that needed **no key from ORC at all** got a vault, and the vault
726
+ then locked the run. There is a third credential source in the form now,
727
+ offered only where it can be true, and pre-selected when the card you pressed
728
+ Connect on says the tool is already signed in.
729
+
730
+ **The passphrase finally has a lifecycle, and a deadline.** A vaulted key needed
731
+ `ORC_EXTRA_KEY` in the environment or nothing, so a green, verified, routed
732
+ connection answered `locked` at wave 1 and the run announced a Claude fallback.
733
+
734
+ - `orc extra session <name> --save --ttl <days>` saves it, **on stdin** —
735
+ `--passphrase <value>` is refused by name, like every other secret here. The
736
+ deadlines are a closed set (1 · 3 · 7 · 14 · 30 · 90 · 180 · 360): no `0`, no
737
+ "forever", and **no auto-extend on use** a deadline that renews itself is
738
+ not a deadline.
739
+ - The cache lives **in the project**, gitignored beside the vault, and is
740
+ encrypted under the pepper that lives in your home directory. **A copy of the
741
+ project folder opens nothing.** That is the one genuine property this file
742
+ has, and it is said out loud wherever the countdown appears along with the
743
+ honest half: while it is saved, anything running as you on this computer can
744
+ open the connection.
745
+ - **`orc extra preflight` is a P0 gate before wave 1.** Active is fine; expiring
746
+ is fine and names the date; **expired or missing STOPS the run**. It never
747
+ falls back `extra_on_failure` is about an endpoint that failed, and a
748
+ deadline you set 30 days ago deserves a stop, not a substitution. The
749
+ credential is deleted and the connection stamped expired; **the routing rows
750
+ survive**, because the bands are work you did.
751
+ - The save modal at connect time **has no exit but Save**, and one destructive
752
+ escape that is named rather than a Cancel.
753
+
754
+ **Extra is visible outside its own panel now.**
755
+
756
+ - **`orc extra lanes`** answers the question a band cannot: *which lane does this
757
+ govern?* `/orc` scores every task; `/orc-fast` pins one executor and resolves
758
+ its band **at both edges**, requiring them to agree. That rule was implemented
759
+ and written down and rendered nowhere. The lane table is code now, mirrored
760
+ against the markdown in both directions by a golden test.
761
+ - **The Flow score table sees Extra.** With `extra: on` it renders the composite
762
+ instead of the Claude ladder a band that cannot route **keeps its row** and
763
+ names its fall-through, and `extra: off` renders byte-identically to before.
764
+ - **`fixed_executor` can name a foreign target** (`extra:<profile>/<provider>/<model>`),
765
+ offered only for verified connections. The session-tier rule is skipped for it
766
+ it is not a Claude model and **the compiled flow says so**, because a rule
767
+ silently disabled is worse than no rule.
768
+ - **`/orc-doc` has its own switch.** `orc doc extra <slug> --set
769
+ off|writer|checker|both`, stored per document, default off. A global setting
770
+ turning Extra on for a throwaway runbook also turned it on for the PRD you
771
+ ship, and a document's voice is the deliverable. `orc doc next` names the
772
+ sections going off Claude **before** the wave.
773
+
774
+ **Three panel defects, and one of them was in every modal.**
775
+
776
+ - A **connected** tool no longer offers Connect. `connected` and `verified` are
777
+ computed by the CLI, never joined in the panel, and the verified card **has no
778
+ Connect button at all** rather than a disabled one.
779
+ - **Scrolling inside a modal scrolled the page behind it** — every modal in the
780
+ app, not just Extra's. Fixed with scroll containment and a body lock.
781
+ - **Two tool cards no longer sit at different heights.** A card declares its rows
782
+ now, so the button in one lines up with the button in the other.
783
+
784
+ **Wording.** The Extra panel's instruction text — labels, hints, errors, gates,
785
+ countdowns, the passphrase modal end to end — is Simplified Technical English,
786
+ with a one-page term list at `bin/webui/i18n/TERMS.md` and a test for the cheap
787
+ half. Rationale prose keeps its voice and only gets shorter: flattening *"it
788
+ stops someone at your keyboard, not someone who copied the file"* makes it true
789
+ and useless. One rule is not negotiable and now has a test: **never simplify a
790
+ CLI-computed value** a simplified state word is a state that does not exist.
791
+
792
+ New: `orc extra session`, `orc extra preflight`, `orc extra lanes`, `orc doc
793
+ extra`, `orc extra dispatch --passphrase-stdin`, and one config key
794
+ (`extra_passphrase_ttl_days`, default 30). `orc extra keyhelp` now carries the
795
+ per-OS command for setting an environment variable with a placeholder, never a
796
+ key, and ORC still refuses to run `setx` or write to your shell profile itself.
797
+
798
+ ---
799
+
800
+ ### v0.51.0 the tools you already have, and a connection that proves itself _(2026-08-22)_
801
+
802
+ **`orc extra` connections.** Two of the things ORC can hand work to are not
803
+ websites they are **programs on your own machine**, and the last release could
804
+ only reach them by hand-typing a binary name into a `custom` profile. They are
805
+ first-class providers now, with a connect box each, a model dropdown built from
806
+ what **your** account can actually reach, and a connection test that proves
807
+ something answered rather than proving a file exists.
808
+
809
+ - **A program can simply not be installed, and the panel says that FIRST.** Four
810
+ states, computed fresh every time and never remembered: `absent`,
811
+ `outdated`, `unauthenticated`, `ready`. An absent tool gets no Connect
812
+ button, no Test button and no model list — every one of those is a button that
813
+ cannot succeed. `orc extra add` refuses too, and names the install command
814
+ instead of leaving you a profile that will never work.
815
+ - **ORC opens your own terminal and runs the install there.** Not a hidden
816
+ background job — inside one, an administrator prompt, a permissions error, an
817
+ 80 MB download and a forty-second wait all look identical: *nothing happened*.
818
+ The exact command is on screen before the button, the window is yours to read
819
+ and Ctrl-C, **ORC never asks for administrator rights**, and if no terminal can
820
+ be opened you get the command to paste rather than a dead button.
821
+ - **One tool has an install-free route and one does not**, and `null` means
822
+ *there is none* rather than *ORC did not look*. The two never render the same.
823
+ - **The connection test is a ladder now, and every rung reads as itself.** Is the
824
+ program there · is it new enough · does it have a sign-in · which models can
825
+ this account reach · and only when you ask **does a real message actually
826
+ come back**, with the round trip, the reply, and the four token counts kept
827
+ separate. Free rungs always run; the paid one is its own button, and what it
828
+ costs is quoted before you press it.
829
+ - **A model that is LISTED is not a model that WORKS.** A live list is what the
830
+ provider offers; an id in it can be dead upstream. `orc extra models <name>
831
+ --test <id>` is the only thing that tells those two apart, and the caveat rides
832
+ beside every dropdown.
833
+ - **Neither local tool says which model answered**, so a quiet substitution is
834
+ invisible on that engine. ORC prints that sentence rather than an empty field
835
+ and one of the two reports three token kinds, not four, so the missing one
836
+ reads as an em dash and never as a zero.
837
+ - **A models list anyone can read is not proof of your key.** A provider that
838
+ serves its catalogue without a credential would otherwise mark a connection
839
+ verified with a typo'd key. That answer is now recorded for what it was and the
840
+ test carries on to something that actually needs the key.
841
+ - **`extra_enabled` cannot be switched on before anything has answered.** It
842
+ would have armed nothing — every task would fall straight back to Claude, so
843
+ the switch read ON and meant OFF. The refusal names what to do next, and the
844
+ Extra panel shows only the connect surfaces until then: no routing table, no
845
+ limits, no cost report.
846
+ - **A fix, not a feature:** every dispatch to one of the two local tools was
847
+ failing, and failing in a way that looked like a bad model id. One of them
848
+ renamed a permission flag and refuses unknown ones outright. ORC picks the flag
849
+ from the version it probed, and a tool that answers with its own help text is
850
+ now reported as a flag problem by name.
851
+ - **ORC never writes another tool's credential store.** Your key stays in ORC's
852
+ vault or in your own environment variable and is handed to the program for each
853
+ run — so nothing global changes, revoking it in ORC actually revokes it, and if
854
+ you already signed that tool in yourself, ORC leaves it alone.
855
+
856
+ ---
857
+
858
+ ### v0.50.0 work that runs somewhere else _(2026-08-22)_
859
+
860
+ **`orc extra`** — a band of ORC's score ladder can now be answered by a
861
+ **non-Claude worker**: DeepSeek, Z.ai (GLM), Moonshot (Kimi), MiniMax, Qwen,
862
+ Xiaomi MiMo, StepFun, SiliconFlow, OpenRouter, a local Ollama, any
863
+ OpenAI-/Anthropic-compatible endpoint you name, or an agentic CLI you already
864
+ have (`opencode`, `codex`). ORC's own session never moves this routes
865
+ **workers**, not the conductor.
866
+
867
+ - **Off by default, and a connection that has never answered can never be used.**
868
+ `orc extra ping` is the gate, it climbs the cheapest rung first (a free model
869
+ list; only then a one-token completion), and it records WHICH rung answered
870
+ "verified by a models list" and "verified by a real completion" are different
871
+ guarantees and one green tick for both would be a lie.
872
+ - **Every armed run says so BEFORE the work starts.** An `extra:` line joins the
873
+ Phase-1 preflight naming how many tasks will cross the boundary and where they
874
+ go. It has no quiet version. The failure this whole subsystem is shaped around
875
+ is not a wrong answer it is work leaving your machine without anybody saying
876
+ so.
877
+ - **A gap in the routing table is not a hole it is Claude**, and it is printed
878
+ with the exact agent it resolves to, so "I left the top band on Opus on
879
+ purpose" and "there is no top band" can never look the same. Overlapping rows
880
+ are refused by name.
881
+ - **Risky work stays.** A task whose plan cites `risk[]` (money, auth, security,
882
+ migration, concurrency, data-integrity) never leaves Claude, and neither does
883
+ anything in an area a boundary card marks REFUSE in `warn` mode as well as
884
+ `block`.
885
+ - **Three engines, and only one composes the request body.** `api` is therefore
886
+ the only one that can enforce the declared-files fence or carry a privacy
887
+ policy, so a return claiming the fence held on the other two is rendered as a
888
+ WARNING: a constraint that was never applied is never reported as kept.
889
+ - **Your key never reaches a command line.** `--key <value>` is refused by name.
890
+ Use an environment variable (recommended) or the encrypted vault —
891
+ AES-256-GCM under a passphrase ORC does not store and cannot recover, stored
892
+ only after a green test, with a countdown that prints every time and a
893
+ self-destruct at ten wrong attempts that keeps the profile. New in this
894
+ release: `orc extra ping --passphrase-stdin` re-tests a key that is already
895
+ stored.
896
+ - **No shipped model ids and no shipped prices.** Both go stale within a quarter
897
+ and both get believed. `orc extra ping` reads the live model list from the
898
+ provider; `orc extra rates` prints the JSON to paste for a price. Until a pair
899
+ has a rate, `usd` reads as an em dash a cost ORC did not price itself is
900
+ never printed.
901
+ - **`orc extra stats`** joins ORC's own traces per profile per band and reports
902
+ four token kinds separately, plus the three things only it can see: a
903
+ SUBSTITUTION (you did not get the model you asked for), a REROUTE (you got the
904
+ model and a different company served it) and a FALLBACK (it did not work and
905
+ Claude finished the job).
906
+ - **A failed foreign dispatch is never a dead run.** It falls back to the Claude
907
+ band that task would have had, announced. `extra_on_failure: stop` is there for
908
+ people who would rather stop than quietly start paying full rates.
909
+ - **New panel: `orc ui` Extra.** The boundary paragraph renders always, never
910
+ behind a click. One 0→100 rail, green where your connection runs the work and
911
+ blue where Claude does, with every unrouted range keeping its slot. Staging a
912
+ change previews it before anything is written. The panel names no provider, no
913
+ model and no agent — it draws what the CLI computed.
914
+ - **The `orc ui` boundary is NARROWED, not broken.** The panel still never runs a
915
+ lane and never does agentic model work; the one model-shaped thing it can
916
+ trigger is a connectivity probe, and even that runs through the CLI in a
917
+ subprocess like every other action. A probe is a diagnostic, the family
918
+ `orc doctor` is in.
919
+ - **Nine config keys**, one canonical contract
920
+ (`_shared/extra-dispatch.md`), a new `EXTRA` trace verb, `orc extra doctor`
921
+ with eleven findings, and a stance stated in exactly one place for every other
922
+ lane — including `/orc-challenge`, which never routes foreign, because swapping
923
+ a lens for a different model does not make the lane cheaper, it changes what is
924
+ being measured.
925
+ - **Also:** the test suite pins `--test-concurrency=8`. At one worker per core,
926
+ the files that spawn real child processes and the one that derives scrypt at
927
+ N=2^17 starved each other and produced failures that looked exactly like
928
+ regressions. Determinism is worth 11% of the wall clock.
929
+
930
+ Setup detail per provider: **[`guides/extra-models.md`](guides/extra-models.md)**.
931
+ A full walkthrough: `orc mock-run orc-extra`.
932
+
933
+ ---
934
+
935
+ ### v0.49.5 house rules are text, and the hand-back writes itself _(2026-08-21)_
936
+
937
+ Two fixes to `/orc-doc`, both the same shape: stop making a person work around
938
+ the tool.
939
+
940
+ - **House rules are a PLAIN TEXT config now, not a form.** The first cut modelled
941
+ a rule as a row one line, one id, a P0/P1/P2 dropdown, an enable flag, added
942
+ one at a time. Nobody's real P0 fits on one line, and filing it as four
943
+ separate rows to keep the CLI's argv simple was the tool asking the user to
944
+ work around it. The ledger is now `.claude/orc/doc-house-rules.md`: three
945
+ headings, and **as much text under each one as you want**, handed to every
946
+ writer verbatim. Open it in your editor, or edit it in **one box** in
947
+ `orc ui` **Docs** no dropdown, no Add button, no per-rule row.
948
+ - **New: `orc doc rules set|add|clear --priority P0 --text "…"`** (multi-line is
949
+ the point), plus `set-all` for the whole file and `--set-file` for a bulk
950
+ replace. `remove`, `enable`, `disable` and `move` are **refused by name** — a
951
+ command that used to work and now does nothing is worse than one that says
952
+ what replaced it.
953
+ - **Migration is lazy, free and non-destructive.** The old `doc-house-rules.json`
954
+ is read once, converted, and **left exactly where it was**. A rule you had
955
+ DISABLED is never resurrected it is left behind and counted in the output.
956
+ - **`RESUME.md` is written by the CLI, on every state change.** It used to be
957
+ prose the orchestrator was told to write at every stop, which is the bet this
958
+ repo has already lost twice: the hand-back you are TOLD to write is the one
959
+ that goes missing on the run a usage limit killed. `doc.json` has exactly one
960
+ writer, so the hand-back hangs off that it exists from `orc doc init` onward
961
+ and is never behind the disk. `orc doc resume-file <slug>` writes it on demand.
962
+ - **Every question `/orc-doc` asks you now ends by pointing at it** (hard rule
963
+ 16): the file path, and the one line to paste into a brand-new session. The
964
+ page itself is written for someone who does not read code what the document
965
+ is, where the files are, what is not written yet, and what happens next.
966
+
967
+ ---
968
+
969
+ ### v0.49.4 the panel was being handed half an answer _(2026-08-20)_
970
+
971
+ One bug, and it could hit any `--json` read big enough.
972
+
973
+ - **Fixed: a large `--json` payload was truncated whenever something read it
974
+ through a pipe.** `emitJson` wrote to stdout and then called `process.exit()`.
975
+ On macOS and Linux a pipe write is asynchronous, so the exit threw away
976
+ whatever had not flushed — and `orc ui` reads every panel through a pipe. On a
977
+ 1,100-file repo `orc wiki coverage --json` computed a perfect 30 KB object, the
978
+ server received the first 9 KB, `JSON.parse` failed, and **Knowledge ▸
979
+ Coverage** reported that the repo had neither a registered wiki nor a git
980
+ repository on a wiki that was FRESH and 39% covered. `orc wiki docs` was hit
981
+ the same way; `wiki status` escaped only because it prints and returns instead
982
+ of exiting. Windows pipes are synchronous, which is why it never showed up in
983
+ development. Every `--json` read now writes through fd 1 synchronously.
984
+ - **The Knowledge panel no longer reports a broken read as an empty repo.** A
985
+ failed request renders the CLI's own reason and output, the way every other
986
+ panel has since v0.49.2 — the generic "it needs a registered wiki and a git
987
+ repository" line is for a repo that actually has neither.
988
+ - **Also: git output is no longer capped at Node's 1 MB default** (v0.49.3),
989
+ which would have truncated `git ls-files` on a repo of roughly 25,000 files.
990
+
991
+ ---
992
+
993
+ ### v0.49.3coverage on a large repo _(2026-08-19)_
994
+
995
+ One fix, and the bigger the repo the more it mattered.
996
+
997
+ - **Fixed: `orc wiki coverage` reported "not a git repository" on a large,
998
+ freshly refreshed wiki.** Every git call ORC makes ran through `spawnSync` on
999
+ Node's **1 MB** default output buffer. `git ls-files` in a big repo prints more
1000
+ than that, the child is killed with `ENOBUFS`, and the exit status comes back
1001
+ `null` — which the code read as *there is no git here*. So `orc ui` ▸
1002
+ **Knowledge** ▸ **Coverage** showed no numbers at all on the repos where the
1003
+ number matters most, and `orc wiki impact` was one wide diff away from the same
1004
+ failure. The buffer is now **256 MB**, and a spawn error is read as an error
1005
+ instead of being inferred from the status code.
1006
+
1007
+ ---
1008
+
1009
+ ### v0.49.2 house rules, a run map before you pay, and three defects _(2026-08-18)_
1010
+
1011
+ Quality of life on `/orc-doc`, plus three bugs — one of which was breaking a
1012
+ panel outright. **Zero new agents, zero new skills.** Everything here obeys the
1013
+ standing rule: **the CLI computes, the panel and the skill render.**
1014
+
1015
+ #### `/orc-doc` house rules
1016
+
1017
+ A **house rule** is your project's own standing instruction about **what a
1018
+ document says and how it reads**: *"open with a one-paragraph summary a PM can
1019
+ read on a phone"*, *"money always carries its currency"*, *"use the customer's
1020
+ words, not the internal table name"*. Before this, the shipped rules were the
1021
+ only rules.
1022
+
1023
+ - Three priorities. **P0** must, and it beats every ORC style preference; **P1**
1024
+ should, and breaking it is recorded as a gap; **P2** prefer.
1025
+ - Stored **verbatim** in `.claude/orc/doc-house-rules.json` one writer,
1026
+ `orc doc rules`, outside `templates/` so `orc update` never touches it. A rule
1027
+ is one line; a multi-line one is refused by name with the hint to add two.
1028
+ - **Each document freezes the set it started with.** If a P0 changes at wave 3,
1029
+ half the document silently no longer complies and nothing on disk says so — so
1030
+ `orc doc rules <slug>` reports frozen-vs-project and **names every rule that
1031
+ was added, changed or removed**, never a "rules changed" boolean.
1032
+ `--sync` re-freezes deliberately and **lists the sections that predate the
1033
+ change**. It re-writes nothing: that would be ORC spending your money applying
1034
+ a rule change retroactively without being asked.
1035
+ - **Read FIRST in every dispatched slice**, above ORC's own rules — that order is
1036
+ the contract.
1037
+ - **The boundary is declared, not detected.** House rules govern content and
1038
+ style; they can never change how the lane RUNS. The CLI cannot parse intent, so
1039
+ it does not pretend to: it prints the boundary everywhere it matters, and a
1040
+ rule that asks for a structural break comes back as `unsupported_request`.
1041
+ - New: `orc doc rules [add|remove|enable|disable|move|--sync|--set-file|--reset]`,
1042
+ a **House rules** card at the top of `orc ui ▸ Docs` (staged and batched, like
1043
+ every other write in the panel), and a `house-rules-drifted` audit finding.
1044
+
1045
+ #### `/orc-doc` four rules ORC applies to every document, all free
1046
+
1047
+ All four are deterministic lint rules, which is what makes them worth having:
1048
+ **no model is ever paid to notice a `TODO`.** Every one is narrow on purpose — a
1049
+ broad rule that argues with the author gets switched off.
1050
+
1051
+ - **No questions or confirmations in the body.** The deliverable answers; it does
1052
+ not ask. `TBD`, `TODO`, `TBA`, *"to be confirmed"*, and a line that is only a
1053
+ question put to you as an approver. **Two exemptions:** fenced code, and a
1054
+ section your own outline calls *open questions / risks / assumptions*.
1055
+ - **Missing information is `N/A` plus one short line, never filler.** A warning,
1056
+ never an error you may have a reason.
1057
+ - **A section well over its planned length is a finding** (1.5× its budget), plus
1058
+ per-section line and word counts in `orc doc lint --json`. Signals, not gates.
1059
+ - **No local-only references.** No `src/foo.ts:42`, no absolute path, no
1060
+ `./relative`, no `localhost`, no `file://`, no link to a local `.md` the
1061
+ person reading a PRD has no repository. Fenced code is always exempt, because a
1062
+ code example that *shows* a path is content. New config `doc_local_refs`
1063
+ (`off|warn|error`, default `error`): a genuinely internal runbook legitimately
1064
+ names local paths, and a lint rule with no switch gets fought instead of used.
1065
+
1066
+ #### `/orc-doc` a supplied template is a cage, not a suggestion
1067
+
1068
+ `--template` set the outline and then nothing stopped a writer adding a heading
1069
+ it never had. It now locks by default: the slice carries the allowed headings,
1070
+ `orc doc lint` errors on a stray one, **`orc doc parts --confirm` refuses the
1071
+ part that grew one and writes nothing**, and `orc doc audit` reports both
1072
+ `template-drift` and `template-moved` (your template file itself changed
1073
+ reported, never auto-synced). `--template-soft` opts out; a shipped base template
1074
+ stays a floor.
1075
+
1076
+ #### `/orc-doc` — what it will cost, and what it did cost
1077
+
1078
+ - **`orc doc forecast <slug>` the run map, once, before the first paid wave.**
1079
+ How many sections, how many waves, how many agents per wave, **how many times
1080
+ it will stop**, and a token range with its sample count. Computed from the same
1081
+ batcher the dispatch uses, so it can never describe a run that will not happen.
1082
+ Every honesty rule of `/orc-budget` is inherited: four token kinds never
1083
+ blended, no dollars without a dated price table, no quota without a known plan
1084
+ and **with no history it refuses rather than invent**, offering the
1085
+ `--naive` price-table floor instead. `orc doc next` names it exactly once; a
1086
+ changed outline or write mode invalidates it.
1087
+ - **`orc doc cost <slug>` — joined across every session the document spanned.**
1088
+ `orc budget actual` works per run, and a document is not a run. Per role and
1089
+ per section, from ORC's traces joined to your local usage transcripts. A slice
1090
+ that covered two sections splits evenly, said out loud; **a section nothing can
1091
+ be joined to reads `—`, never `0`.** `unattributed` is always printed.
1092
+ - Both render in `orc ui ▸ Docs` with a stacked four-kind token bar, so
1093
+ cache-read stays visibly separate from the rest.
1094
+
1095
+ #### `/orc-doc` an edit round tells you where to look
1096
+
1097
+ `orc doc lint <slug> --section <id>` lints one **section file** and returns
1098
+ **part-local** line numbers, and every finding on an edit-round slice carries its
1099
+ file and line. The skill prints one line per finding
1100
+ (`sections/03-scope.md · line 42 · long-sentence`) and, after the round, each
1101
+ file it touched. The compiled `document.md` line number is deliberately never
1102
+ carried: it is stale the moment anything is written.
1103
+
1104
+ #### Fixed — the Overview card printed over itself
1105
+
1106
+ `.run-card` is a four-column grid (caret · chip · mid · age) and the Overview
1107
+ built a card with **three children and no caret**, so the chip landed in the 16px
1108
+ caret column and printed straight over an 88px slug, which wrapped one word per
1109
+ line. A grid never complains. Every variant now declares its own column count —
1110
+ `.no-caret` for a row that navigates, `.has-extra` for an optional second chip —
1111
+ and the same collision in the Docs list (from its "you edited it" chip) is fixed
1112
+ the same way. The age column now carries the age `run list --json` always knew.
1113
+
1114
+ #### Fixed — a run could never be marked done
1115
+
1116
+ `RESUME.md` existing IS the "unfinished" flag, and ORC deletes it at `FINISH`. So
1117
+ a run you abandoned was waiting **forever**: `orc resume` kept offering it, the
1118
+ Overview kept counting it, and the upgrade preview kept refusing with "N run(s)
1119
+ are still waiting" — with no way out short of deleting a file by hand.
1120
+
1121
+ `orc run close <slug> --reason "<why>"` **moves** `RESUME.md` to
1122
+ `RESUME.closed.md` and records why. **It deletes nothing**, and `orc run reopen`
1123
+ puts it back byte for byte. The new state is **`closed`**, deliberately not
1124
+ `done`: the disk cannot prove a run finished, only that you said you were
1125
+ finished with it. A reason is required — a state change nobody wrote a reason for
1126
+ is a state nobody can audit. Everything else follows from one boolean: `resume`
1127
+ skips it, `run list` keeps the row *and* its reason, and the upgrade unblocks.
1128
+ Buttons for both in `orc ui ▸ Runs`, and inline on the Overview card that was
1129
+ complaining.
1130
+
1131
+ #### Fixed — one corrupt challenge ledger 500'd the whole panel
1132
+
1133
+ Two crash classes: a ledger truncated by a killed session, and a ledger with no
1134
+ `goals` key. Both threw a Node stack with nothing parseable on stdout, so
1135
+ `orc ui Challenge` showed a bare 500 and **every healthy cycle disappeared
1136
+ with the broken one**, which is the opposite of what a listing is for.
1137
+
1138
+ - A broken cycle is now a **row** that reads `UNREADABLE` and carries the parse
1139
+ error. It is a list-level state: it never reaches the pass gate and never
1140
+ claims a verdict.
1141
+ - **No `--json` read can emit a stack trace any more.** A throw comes back as
1142
+ `{ok: false, reason: "crashed", command, error, hint}` with its own exit code
1143
+ every `--json` route inherits it.
1144
+ - A 500 from the panel's API now carries the CLI's own reason, and the panel
1145
+ renders it. A 500 with no message is what you actually saw.
1146
+
1147
+ ### v0.49.1 — the challenge council, and a `--json` that stops throwing things away _(2026-08-18)_
1148
+
1149
+ One release, two workstreams, and **zero new skills**. They ship together because
1150
+ they are the same defect seen twice: **ORC computes far more than it shows.**
1151
+ `computeWikiFreshness` builds a per-doc table that `--json` threw away;
1152
+ `challenge record` computes per-dimension, per-severity, per-iteration detail
1153
+ that the panel rendered as one chip. Both halves are "stop discarding what you
1154
+ already computed" and only one of them also adds new thinking.
1155
+
1156
+ ---
1157
+
1158
+ ## Part A the challenge council
1159
+
1160
+ ### Five more ways of looking, and none of them is ORC's to choose
1161
+
1162
+ `/orc-challenge` had one grounded opinion (the judge) and one blind one (the cold
1163
+ reader), and both read the artifact the same way: *does this document do what a
1164
+ document is supposed to do?* Five ways of looking were missing, and each one is
1165
+ missed for a different reason:
1166
+
1167
+ | Role | It asks | It fails when |
1168
+ |---|---|---|
1169
+ | **The Contrarian** | where is the fatal flaw? | it assumes the artifact is fine and stops looking |
1170
+ | **The First Principles Thinker** | are we even solving the right problem? | it accepts the framing it was handed |
1171
+ | **The Expansionist** | what is being undervalued here? | it only counts what is wrong |
1172
+ | **The Outsider** | what does this assume I already know? | it is an expert and cannot un-know things |
1173
+ | **The Executor** | what do you actually do on Monday morning? | it grades the theory and never the first step |
1174
+
1175
+ > **A lens raises; only the judge resolves. ORC proposes the council; the user
1176
+ > picks it.**
1177
+
1178
+ **`a lane that picks its own council` has broken this contract** registered as
1179
+ the fourth member of the family with `a lane that answers its own interview
1180
+ question`, `a lane that picks its own favourite` and `a lane that fixes what it
1181
+ judged`. A council chosen by ORC is ORC deciding **which kinds of criticism the
1182
+ user is allowed to hear**, which is a bigger decision than any single finding in
1183
+ the run. So `orc challenge init --council` has **no default** and refuses by
1184
+ name, exactly like `--goal` since v0.47.0:
1185
+
1186
+ ```
1187
+ --council is required and has no default. ORC SUGGESTS a roster (from the kind
1188
+ and the goal); the user PICKS it. […] Suggested for --kind tsd:
1189
+ reader,contrarian,executor.
1190
+ (a lane that picks its own council has broken this contract)
1191
+ ```
1192
+
1193
+ `none` is a first-class answer and reproduces the v0.47.0 review exactly. The
1194
+ cost is stated in **dispatches**, never in dollars — `/orc-budget`'s rule: no
1195
+ dollar figure without a dated price table.
1196
+
1197
+ ### Two of them cannot produce a finding without lying
1198
+
1199
+ This is the most important decision in the release.
1200
+
1201
+ **The expansionist.** A finding must carry `serves` the goal element it
1202
+ advances and `record` DROPS one without it. Its entire brief is *"what upside
1203
+ is everyone missing?"*, which by construction is **not** in the stated goal.
1204
+ Given a `serves` field it would either invent a goal element or be silently
1205
+ dropped. So it returns an **opportunity**: no severity, never in `findings[]`,
1206
+ never near the pass gate, always with a `first_step` and a route
1207
+ (`brainstorm | pact | grill | none`). It is conserved — `--take` or `--drop`,
1208
+ both requiring a reason and **this lane never builds one**.
1209
+
1210
+ **The first-principles thinker.** Its most valuable output is *"you are asking
1211
+ the wrong question entirely"*, and in this lane the question is the **frozen
1212
+ goal**. A finding is measured against the goal; a premise challenge disputes the
1213
+ **yardstick**. Those cannot be the same object. It returns a **premise**, and
1214
+ exactly two resolutions exist, both a human's: adopt it (`orc challenge goals
1215
+ --set`, a `regoal` that bumps `goals.version`) or dismiss it with a mandatory
1216
+ reason that stays in the report forever. **The judge never sees that report**
1217
+ handing a judge a document arguing the frozen goal is wrong would bend every
1218
+ finding it produced afterwards.
1219
+
1220
+ > The three finding lenses feed **the judge**. The two non-finding lenses feed
1221
+ > **the user**. That sentence is the whole architecture.
1222
+
1223
+ ### The gate that makes five extra reviewers safe
1224
+
1225
+ The obvious failure of adding five reviewers is that the judge quietly ignores
1226
+ four of them and the run looks identical while costing five times more.
1227
+
1228
+ > **Every id the council raised must appear in the judge's return with exactly
1229
+ > ONE disposition and a reason. `council_coverage_pct` must be 100.**
1230
+
1231
+ That is conservation applied to **input** instead of to carry-forward, and the
1232
+ CLI enforces it without reading a word of prose: the orchestrator writes a
1233
+ machine JSON beside every council report, and **`orc challenge record` reads that
1234
+ directory itself**. The judge cannot shrink the set by omission, because the set
1235
+ was never the judge's to report.
1236
+
1237
+ ```
1238
+ malformed verdict — council coverage is below 100% every id the council
1239
+ raised needs exactly ONE disposition (adopted | merged | rejected |
1240
+ out-of-goal). Missing: O-003
1241
+ ```
1242
+
1243
+ **An adopted finding keeps the raiser's id.** `C-004` stays `C-004` in the
1244
+ verdict, in the report, in iteration 9 which is what lets the panel say *"the
1245
+ contrarian raised four of the six blockers this iteration"*, and how a user finds
1246
+ out within two rounds whether a lens is worth its money.
1247
+
1248
+ **PASS is computed exactly as before.** An adopted council finding is an ordinary
1249
+ finding from that moment on; `challengeBlocking()`, `challengeOpen()`,
1250
+ `challengeCounts()` and `challengeStateOf()` are untouched. The pass gate learns
1251
+ nothing about the council.
1252
+
1253
+ ### A selected role is never silently absent
1254
+
1255
+ Rule 6 (`NOT-CHECKED` is never silent), extended from dimensions to roles. A
1256
+ roster lens returns either a report or an explicit `{ "lens": …, "ran": false,
1257
+ "reason": }`, and silence is rejected by name:
1258
+
1259
+ ```
1260
+ malformed verdict executor is on the roster but returned neither a report
1261
+ nor an explicit { "lens": "executor", "ran": false, "reason": "…" }.
1262
+ A selected role is never silently absent.
1263
+ ```
1264
+
1265
+ The trace carries it too, so `orc stats` and `/orc-retro` see a NOT-RUN lens and
1266
+ not only the panel:
1267
+
1268
+ ```
1269
+ CHALLENGE iter=2 findings=P0:1/P1:3/P2:6 coverage=100% council=4/5 raised=C:6,O:3,E:2 adopted=9 verdict=FAIL
1270
+ ```
1271
+
1272
+ ### Effort is a measurement, not a cost choice
1273
+
1274
+ `outsider` is `low` for the same reason the cold reader is: a harder-thinking
1275
+ outsider reasons its way *around* an unexplained acronym and reports the document
1276
+ is fine, which is exactly the gap the instrument exists to find. **Nothing may
1277
+ ever upgrade it.** `contrarian` is `high` because at low effort it returns the
1278
+ three surface complaints the free lint already caught for nothing.
1279
+
1280
+ That is why there is **no model or effort config key**: a key that lets
1281
+ `outsider: low` be tuned is a key that lets the instrument be broken.
1282
+
1283
+ All seven lenses are `claude-opus-5`, so **`opus5_only` is a no-op for this lane
1284
+ it is unaffected, not exempt** and the agent count moves 46 → 51 with no paired
1285
+ variants.
1286
+
1287
+ ### The reader / outsider seam
1288
+
1289
+ These two are the closest pair in ORC and the one place this release could have
1290
+ shipped a duplicate instrument. The distinction is structural:
1291
+
1292
+ | | `reader` | `outsider` |
1293
+ |---|---|---|
1294
+ | Told the audience | **yes** | **no** |
1295
+ | What it generates | 8–15 questions the artifact *promised* to answer | nothing — it reacts to what is on the page |
1296
+ | What it returns | a **scored** questionnaire (`8/12`) | an **unscored** ranked list of assumed knowledge |
1297
+ | The measurement | *can this be answered from the page?* | *what does this page assume you already know?* |
1298
+
1299
+ They are dispatched with no knowledge of each other. Where they agree, that is
1300
+ recorded as `corroborated_by` the strongest comprehension evidence the lane can
1301
+ produce, and **never an automatic severity bump**.
1302
+
1303
+ ### The roster is frozen, and `council: null` is a real state
1304
+
1305
+ Ledger `version: 2`, additive: every v1 key keeps its name, meaning and position.
1306
+ The roster is a per-cycle **frozen** decision changed only by a recorded
1307
+ `recouncil` event, which bumps `council_version` exactly like `goals.version`
1308
+ and the iteration rail draws a **third** version break for it, because comparing
1309
+ an iteration judged by three lenses to one judged by six is not a comparison.
1310
+
1311
+ **There is no `challenge_council` config key.** A global default roster would
1312
+ silently answer the one question this release exists to ask. A cycle opened
1313
+ before v0.49.1 reads back with `council: null` and `record` refuses the next
1314
+ iteration by name until it is answered — `orc challenge council <slug>` exits 1
1315
+ for that state, because **UNSET is an answer, not an error**.
1316
+
1317
+ ### New commands
1318
+
1319
+ | Command | Does |
1320
+ |---|---|
1321
+ | `orc challenge roles [--kind k] [--json]` | the lens catalogue. Static — it works with no cycle at all |
1322
+ | `orc challenge council <slug> [--json]` | the frozen roster + per-iteration participation (0 set · 1 unset · 3 unknown) |
1323
+ | `orc challenge council <slug> --set <csv\|all\|none> --reason "…"` | a recorded `recouncil` |
1324
+ | `orc challenge note <slug> --from <json>` | opportunities and premises ONLY — it refuses a `findings[]` key by name |
1325
+ | `orc challenge premise <slug> <id> --dismiss --reason "…"` | |
1326
+ | `orc challenge opportunity <slug> <id> --take\|--drop --reason "…"` | |
1327
+
1328
+ ### The panel
1329
+
1330
+ It **derives nothing**: it does not name a lens, does not know which class
1331
+ blocks, does not compute a disposition and does not decide the suggestion. A test
1332
+ greps the panel for every lens display name, every disposition word and every
1333
+ agent name and fails if it finds one.
1334
+
1335
+ New: a **Council card** directly under the goal (a NOT-RUN row keeps its slot
1336
+ with its reason; a NOT-SELECTED row is muted with the line that would add it; the
1337
+ council executor's `monday_morning` list sits here, because it is the most
1338
+ legible thing this lane produces for a non-engineer); a **premise card** that is
1339
+ the loudest thing on the panel when one is open and sits *above* the findings; an
1340
+ **opportunities card** with no severity colour anywhere in it; a lens chip and an
1341
+ `also found by` chip on every finding; and a per-lens legend under the
1342
+ convergence chart.
1343
+
1344
+ There is deliberately **no route for `council --set`** changing the roster is a
1345
+ decision with a recorded reason the *lane* takes in conversation.
1346
+
1347
+ ### Deliberately absent
1348
+
1349
+ - **An anonymised peer-review round.** It doubles the dispatch count, and the
1350
+ judge's adoption pass already reconciles the lenses. The payoff *"two
1351
+ advisors independently hit the same thing"* — is `corroborated_by[]` at zero
1352
+ extra cost.
1353
+ - **A chairman agent.** ORC already has one: the advisor groups findings by root
1354
+ cause and orders the fix. Rule 5 still holds no advisor on PASS.
1355
+ - **A `challenge_council` key, any model or effort key, a `block` mode on a
1356
+ council output, a loop cap, and auto-severity from corroboration.**
1357
+
1358
+ ---
1359
+
1360
+ ## Part B the knowledge deepening
1361
+
1362
+ ### `--json is not a summary`
1363
+
1364
+ > A read's `--json` is the WHOLE computed object, not a summary. **A field the
1365
+ > human path prints and the JSON omits is drift — and it is drift no lint can
1366
+ > see, because both halves live in one function.**
1367
+
1368
+ `wikiStatus()` computes `computeWikiFreshness(...)` and the terminal branch
1369
+ printed the per-doc FRESH/AGING/STALE counts, **the worst doc's filename** (the
1370
+ thing actually pinning the tier), the top five stale docs with their own
1371
+ distances, and the crosslink boundary state. The `--json` branch emitted five
1372
+ scalars and `blind` **as a count**. The panel therefore *could not* be as
1373
+ detailed as the terminal, no matter how it was written.
1374
+
1375
+ `wiki status --json` now carries `counts`, `worst`, `per_doc[]`, `blind_spot` as
1376
+ the **file list it always was**, `orientation`, `crosslink`, and `free_repairs`
1377
+ reused verbatim from `wiki plan` a user must never be able to pay for what a
1378
+ free step fixes. **Every legacy key keeps its name, position and meaning** (`orc
1379
+ doctor`, the overview tile and `_shared/detecting-artifacts.md` all read them)
1380
+ and the exit code stays 0 in every state.
1381
+
1382
+ ### You can finally see what the wiki contains
1383
+
1384
+ `orc wiki` had six subcommands and **not one of them listed the docs**. A user
1385
+ could learn the wiki was STALE with 14 docs and 47 commits of drift, and could
1386
+ not learn what any of those 14 docs was about.
1387
+
1388
+ | Command | Returns | Exit |
1389
+ |---|---|---|
1390
+ | `orc wiki docs [--json]` | the doc table: tier, its OWN distance, covers, usage, tags, retire hint | 0 · 1 none · 3 unregistered |
1391
+ | `orc wiki show <doc> [--body]` | one doc + its tags + the free repairs that apply to IT | 0 · 2 unreadable · 3 unknown |
1392
+ | `orc wiki coverage [--json]` | % of tracked files covered by ≥1 doc, uncovered set by DIRECTORY | 0 full · 1 gaps |
1393
+ | `orc pattern show <lang> [--body]` | headings, conventions vs invariants, flagged conflicts | 0 · 1 absent · 2 unknown key |
1394
+ | `orc gotcha show <id>` | one entry, EVERY field | 0 · 3 unknown |
1395
+ | `orc gotcha list --archived` | the archive | 0 · 1 none |
1396
+ | `orc gotcha prune --dry-run` | exactly what eviction would archive, and why | 0 none · 1 would prune |
1397
+
1398
+ **`orc wiki coverage` is a REPORT and never a gate.** No threshold, no config
1399
+ key, nothing branches on it a repo that deliberately documents four subsystems
1400
+ out of forty is not broken, and a coverage percentage that starts nagging becomes
1401
+ a number people game. The uncovered set is collapsed to directories and ranked by
1402
+ file count, because *"240 uncovered files, all in `vendor/`"* and *"12 uncovered
1403
+ files, all in `src/payments/`"* are opposite situations.
1404
+
1405
+ **`--body` is opt-in** on both `wiki show` and `pattern show`: prose is returned
1406
+ only on an explicit request, exactly one artifact at a time, rendered as DOM and
1407
+ never as HTML.
1408
+
1409
+ **`orc pattern show` invents nothing.** The codifier may not write a parseable
1410
+ header today; with none it returns `headered: false` plus the headings it could
1411
+ parse, and says so in one line. It **never** derives a "codified at" from the
1412
+ file's mtime the `/orc-pact` UNCHECKABLE rule.
1413
+
1414
+ ### Two doctor findings, and the restraint is the design
1415
+
1416
+ | id | Warns when | Fix |
1417
+ |---|---|---|
1418
+ | `wiki-unregistered` | the wiki is unregistered, drifted or corrupt | `orc wiki sync` — free, instant, and until it is done nothing can read the wiki at all |
1419
+ | `wiki-debt` | tier is **STALE** and `wiki plan` has pending rows | `/orc-wiki refresh --top 2` |
1420
+
1421
+ **`wiki-debt` fires on STALE and never on AGING.** Aging is a normal state every
1422
+ living repo passes through, and a doctor that warns about it is a doctor people
1423
+ learn to ignore. Deliberately not added: `pattern-missing` — a project with no
1424
+ cached pattern is not misconfigured, and warning about it would be ORC nagging
1425
+ for a paid scan.
1426
+
1427
+ Both route to the Knowledge panel: *a caution routes to the panel that can CLEAR
1428
+ it*, and `orc wiki sync` is a button there.
1429
+
1430
+ ### `orc ui Knowledge` five tabs
1431
+
1432
+ ```
1433
+ Knowledge [ Wiki ] [ Coverage ] [ Code patterns ] [ Memory ] [ Peers ]
1434
+ ```
1435
+
1436
+ A header strip renders above them all — tier · docs · covered % · blind ·
1437
+ pending · patterns · repair notes — and **a value the CLI could not compute
1438
+ renders as an em dash, never as a guess.**
1439
+
1440
+ - **Wiki** the tier card with the **worst doc named** (a hash is not something
1441
+ anybody can go and refresh), the per-doc counts as a stacked bar, free repairs
1442
+ above everything priced, and **the doc table**. A row expands in place, one at
1443
+ a time, detail fetched on first open.
1444
+ - **Coverage** one honestly-qualified number, the uncovered set by directory,
1445
+ the structural blind spot as the file list it always was, and one line that is
1446
+ not optional chrome: coverage is a report, not a target.
1447
+ - **Code patterns** per language, with **the conflicts the codifier flagged in
1448
+ their own block**: they are the most decision-shaped thing in the file and were
1449
+ invisible outside it. Reveal shows the text that is injected literally into
1450
+ every executor slice; a user who cannot read it cannot trust it.
1451
+ - **Memory** every field the CLI already emitted, headroom against
1452
+ `gotchas_max`, and a **preview-then-apply prune that names every entry** (a
1453
+ count is not consent). The archive is reachable and labelled recoverable.
1454
+ - **Peers** — compact, read-only, every word the CLI's. It links to Crosslink and
1455
+ never duplicates its editor: one boundary, one picture.
1456
+
1457
+ ### Guards
1458
+
1459
+ Five new agent files named explicitly in `verify-package.js` (floor 46 → 51,
1460
+ skills unchanged at 38); five new contract-lint entries; a golden test comparing
1461
+ `CHALLENGE_LENS_META` to `council.md`'s roster table; and one test per new read,
1462
+ because `--json is not a summary` is drift no lint can catch.
1463
+
1464
+ `css/panels/knowledge.css` is a new file, so it is `<link>`ed in `app.html` **and**
1465
+ named in `verify-package.js` the manifest is the load order, and a file the
1466
+ manifest forgot is a file the test suite never sees.
1467
+
1468
+ ---
1469
+
1470
+ ### v0.49.0 the document is a folder, and the file is a build artifact _(2026-08-17)_
1471
+
1472
+ `/orc-doc` only. No other lane changes, and **zero new agents**.
1473
+
1474
+ Three quarters of what this release is about already existed: `orc doc plan`
1475
+ already wrote one part file per section, the ids were already number-then-name,
1476
+ the split already cut on `## ` alone, and `orc doc assemble` was already pure
1477
+ Node **zero model tokens, and it always was**. Anyone who tells you this
1478
+ release made compiling cheaper is selling something.
1479
+
1480
+ What was wrong was the direction of the arrow.
1481
+
1482
+ #### `sections/` is the source of truth
1483
+
1484
+ `.work/` was scratch and `document.md` was the truth, so after the first
1485
+ assemble every later change was *extract* (copy a section OUT of the monolith) →
1486
+ edit → *splice* (write it back IN). The section files existed and were dead. A
1487
+ resumed session, an update and a re-check all routed through the 10,000-line
1488
+ file.
1489
+
1490
+ Now each section lives in `sections/<NN>-<slug>.md` a real, visible folder you
1491
+ can open, edit and read in a pull request and **`document.md` is a build
1492
+ artifact** that `orc doc compile` rebuilds from those files, for free, when you
1493
+ ask. `orc doc split` goes the other way and recovers the sections from a
1494
+ document a human reshaped by hand; **`split` then `compile` reproduces the file
1495
+ byte for byte**, and there is a test.
1496
+
1497
+ The join key is the **filename**. No comment markers inside the files: an HTML
1498
+ comment is a lint error in this lane and mangles on a Notion or Google Docs
1499
+ import, and the deliverable's cleanliness is the lane's entire product. A marker
1500
+ that buys nothing costs the import.
1501
+
1502
+ #### You can look before you buy the rest
1503
+
1504
+ `orc doc compile --partial` writes exactly the sections that exist and **names
1505
+ the rest outside the document** nothing is ever stubbed into the deliverable.
1506
+ Paired with the new `doc_write_mode` (`ask` · `partial` · `all`, asked once per
1507
+ run and stored), `orc doc plan --role write` returns **wave 1 only**, with
1508
+ `more_waves: N`. You read what it wrote, and waves 2..N are bought only if wave 1
1509
+ was right. That is the single biggest saving in the lane, and it has nothing to
1510
+ do with the compile.
1511
+
1512
+ #### A wave is a stop you can walk away from
1513
+
1514
+ The write loop used to live in the orchestrator's head, and `/orc-doc`'s
1515
+ `RESUME.md` sat in the document folder where `orc resume` and `orc run list`
1516
+ never look carrying a `## Where it stands:` line that the line-anchored parser
1517
+ **could never match**, and no phase and no wave even if it had.
1518
+
1519
+ All four are fixed. `RESUME.md` moves to `{run_dir}/{slug}/`, the line is at
1520
+ column 0 and gains a phase D6 · wave 2 of 7` suffix (the byte-stable prefix is
1521
+ untouched), and a test feeds the shipped template to the real `parseStands`. The
1522
+ section files on disk ARE the progress, so `K of N` is **computed** by counting
1523
+ waves whose sections are all hash-confirmed. A part on disk that no validated
1524
+ return ever confirmed is `unconfirmed` exactly what a usage limit leaves and
1525
+ it is re-written, never shipped.
1526
+
1527
+ #### The deliverable carries content only
1528
+
1529
+ `> **Open:**` and `> **Assumption:**` lines are no longer written into your
1530
+ document, and the section state no longer sniffs the body text for them. This
1531
+ does not relax "never invent a fact"; it moves where the honesty is written down.
1532
+ A gap goes to `orc doc log --kind gap` and lands in a derived `gaps.md`, and is
1533
+ raised with you.
1534
+
1535
+ `orc doc lint` gains `annotation-in-body` as an **error**, matching an exact,
1536
+ narrow set of ORC's own markers and nothing else a line of yours beginning
1537
+ "Note:" is content and is never flagged. `compile` **reports** every match and
1538
+ never silently strips one: we cannot tell whose line it is.
1539
+
1540
+ #### A live bug, fixed by construction
1541
+
1542
+ A slice covering two sections wrote **one** file, named after the first, while
1543
+ `assemble` looked one up per outline id. The second section's file never existed:
1544
+ if it was required, assemble refused forever; if it was optional, it silently
1545
+ vanished from the deliverable. **One file per section** now, per slice entry, with
1546
+ a regression test.
1547
+
1548
+ #### A section too big for one file
1549
+
1550
+ It splits **underneath** `sections/04-detailed-design/{00-head,01-data-model,…}.md`
1551
+ — cut on its own `### ` headings, which `docScan` already collected and merely
1552
+ filtered out. The reader never knows: the compiled document has exactly one `## `
1553
+ for it, and `orc doc map`, `lint`, `ship` and `audit` are completely unchanged.
1554
+ Five refuse-and-name rules make the nesting safe, and a changed sub-part is
1555
+ detected on its own, so a re-check inside a 900-line section reads ~150 lines.
1556
+
1557
+ **No new config key** for it: `doc_max_lines_per_agent` is already the threshold.
1558
+
1559
+ #### The rest
1560
+
1561
+ - **`doc_max_parallel` hard cap is now 2** (default 2, was 4/4). A larger value
1562
+ is clamped and the clamp is announced.
1563
+ - **`orc doc parts`** is the new wave-boundary read, and the one that works
1564
+ before a single compile has ever run. `--confirm <ids>` is how a validated
1565
+ return becomes a recorded hash.
1566
+ - **`orc doc ship` refuses on a stale `document.md`**, naming the sections —
1567
+ coverage-relative, one step earlier than `shipped-drifted`.
1568
+ - **`orc doc audit`** gains `part-missing`, `part-orphan`, `part-misnumbered`,
1569
+ `part-unconfirmed`, `subpart-bad-level`, `document-stale`,
1570
+ `annotation-in-body`, `legacy-work` and `resume-misplaced`.
1571
+ - **`orc doc outline --set` renames the files on disk** when a renumber moves
1572
+ them, in the same step.
1573
+ - **A checker now reads ONE bounded part file**, so there is no line arithmetic
1574
+ anywhere in the check loop.
1575
+ - The Docs panel gains a **Section files** card with nested sub-part rows, a wave
1576
+ strip, a compile button and a migrate button. It derives nothing new: the CLI's
1577
+ state words, verbatim.
1578
+
1579
+ #### Nothing is lost on the way
1580
+
1581
+ `doc.json` goes to `version: 2` and a v1 document migrates the first time you
1582
+ touch it lazy, free, idempotent, non-destructive. `document.md` is **never
1583
+ deleted** (it becomes the build artifact, and starts life fresh rather than
1584
+ stale), a pending extract wins as the newer edit, an `> **Open:**` stub does not
1585
+ survive, `RESUME.md` is moved and its prefix stripped, and an **unparseable**
1586
+ document is REFUSED with `version` left at 1 — a guessed structure is worse than
1587
+ none. `assemble`, `extract` and `splice` survive as thin aliases for one release,
1588
+ with their exit codes preserved.
1589
+
1590
+ ---
1591
+
1592
+ ### v0.48.1 one file per thing, and a document that can be finished _(2026-08-16)_
1593
+
1594
+ Two halves, deliberately kept separate so that **any** behaviour difference
1595
+ observed after this release is attributable to the second one and to nothing
1596
+ else.
1597
+
1598
+ #### The panel is an architecture now
1599
+
1600
+ `bin/webui/` was four monoliths: a 6 500-line `app.js`, a 2 500-line
1601
+ stylesheet, a 1 700-line fixture module and two 800-key string tables. Any
1602
+ change to one panel meant paging through all of it to find three places.
1603
+
1604
+ It is now ~60 named files — one per panel, one per CSS layer, one per i18n
1605
+ namespace, one per fixture set and the **filename is the load order**, so a
1606
+ future session never has to reason about dependencies.
1607
+
1608
+ - **Classic scripts, not ES modules,** and the constraint that decided it:
1609
+ `serve.js` requires the per-launch token on every static request, and **an
1610
+ `import` carries no query string**. A module graph would 401 on every import
1611
+ unless static auth were weakened, which was not on the table. Classic scripts
1612
+ also share one global lexical scope, so the split added no `import`/`export`
1613
+ and changed no call site.
1614
+ - **`serve.js` builds its static map from a one-time walk at boot.** A request
1615
+ path is still a KEY LOOKUP in a frozen table, never a path join — directory
1616
+ traversal stays structurally impossible. Server-side code (`serve.js`,
1617
+ `api.js`, `fixtures/`) is never served.
1618
+ - **Token stamping is generic.** Naming two files was fine when there were two;
1619
+ with ~55 the pattern has to be the rule, or the next `<script>` tag someone
1620
+ adds 401s silently. A test parses `app.html` and asserts every reference comes
1621
+ back stamped **and** resolves.
1622
+ - **`06-responsive.css` and `04-motion.css` load last, and that is
1623
+ load-bearing.** Several reduced-motion rules are deliberately not
1624
+ `!important` `.vault-pulse` and `.step-flow` are removed with
1625
+ `display: none`, because capping an infinite animation to one iteration
1626
+ freezes it mid-cycle so an equal-specificity rule loading afterwards would
1627
+ win on order and switch the animation back on.
1628
+ - **`verify-package.js` names every file AND asserts set equality** with the
1629
+ directory, in both directions: the agent-file pattern, applied to the panel.
1630
+ - The test suite is split to match (`test/cli/`, `test/lanes/`, `test/webui/`),
1631
+ using an `appJs()` / `appCss()` helper that concatenates exactly what
1632
+ `app.html` loads — so a file the manifest forgot cannot hide behind a passing
1633
+ suite.
1634
+
1635
+ **No behaviour changed.** All 274 tests pass, all 17 panels render in both
1636
+ themes and both languages with zero console errors, and the guided tour runs end
1637
+ to end.
1638
+
1639
+ #### `/orc-doc` has a finish line
1640
+
1641
+ - **`orc doc next`** turns the pipeline from something the orchestrator
1642
+ REMEMBERS into something the CLI COMPUTES the Flow-stepper shape, and for
1643
+ the same reason: D6–D9 was prose a session had to hold in its head across a
1644
+ resume that might be months later in a fresh context. Exit **0** = an action
1645
+ is available (`command`, plus `paid` so a caller knows button vs copy-able
1646
+ command), **1** = waiting on a human decision, **named** in `blocked_by`,
1647
+ **2** = unknown slug.
1648
+ - **`orc doc ship` records delivery as a DECISION** (`/orc-pact`'s rule) while
1649
+ the resulting state stays **COMPUTED** (`/orc-challenge`'s rule). `--where`
1650
+ has **no default** "shipped" with nowhere to point at is not a fact, it is a
1651
+ feeling and shipping an incomplete document needs `--force --reason`,
1652
+ recorded verbatim. `unship` needs a reason and keeps the old record in
1653
+ `ship_history[]`.
1654
+ - **`shipped-drifted` names the sections that moved,** by diffing the recorded
1655
+ per-section hashes against the live map. Coverage-relative, the
1656
+ `computeWikiFreshness` lesson applied to a document: a whole-file "something
1657
+ changed" cannot tell you what to re-read. It exits **1**, because the document
1658
+ moved after it was delivered and that is work.
1659
+ - **`orc doc audit`** reports every drift class from disk an extract never
1660
+ spliced back, an extract whose section moved under it, a heading a hand edit
1661
+ deleted or added, a target that no longer matches the file, a reference file
1662
+ that moved, a cycle count that disagrees with itself each with a fix command
1663
+ and the panel that can clear it. A hand-edited section is **reported and never
1664
+ counted as a finding**: flagging it would teach people to stop editing their
1665
+ own document. `orc doctor` gains a `doc-drifted` finding routed to Docs.
1666
+
1667
+ #### And it remembers what you asked for
1668
+
1669
+ This was a **data** gap, not a rendering one. `created_at` existed and
1670
+ `orc doc show --json` never emitted it; `context.md` and `context-sources.md`
1671
+ were files the CLI never opened; and what the user actually ASKED FOR, in order,
1672
+ across every session, lived nowhere at all.
1673
+
1674
+ - **`orc doc log` / `journal`** record and serve it. The journal merges four
1675
+ sources into one chronological array with the provenance of every row attached
1676
+ `recorded` (the user's own words, verbatim), `derived` (a cycle, a ship
1677
+ record), `observed` (a section that turned `user-edited`) and **it never
1678
+ invents an entry**: a cycle that ran with nothing logged renders as an explicit
1679
+ gap, never a plausible reconstruction from file mtimes. The `/orc-pact`
1680
+ UNCHECKABLE rule: not knowing is an answer, and faking it teaches people to
1681
+ distrust the rows that are real.
1682
+ - **`orc doc context`** returns the frozen brief the verbatim request first,
1683
+ because that is the memory-regain payload plus the D2 reference table with a
1684
+ live state per file: `ok`, `MISSING`, `SOURCE-DRIFTED`. A source is stale
1685
+ only when THAT FILE moved, never because the repository did, and it is a
1686
+ **warning, never an error**: a frozen context is *supposed* to be old.
1687
+ - **`orc doc read`** is a reader for the HUMAN and the rule table says out
1688
+ loud that the orchestrator never runs it, registered as a contract token so
1689
+ the sentence cannot quietly disappear.
1690
+ - **The Docs panel is rebuilt around this: MEMORY FIRST, state second.** The
1691
+ header strip, the brief, the reference files and the journal come before the
1692
+ ribbon because a user coming back after three weeks did not come back to ask
1693
+ what state the document is in.
1694
+
1695
+ #### One more way in
1696
+
1697
+ D4 and D5 gain a `RETURN-TO` suspend into **`/orc-grill`** gated on all
1698
+ three of the `_shared/lane-suspend.md` tests (a DECISION not a fact, a
1699
+ PREREQUISITE that changes the option set, a SUBTREE with more than one question
1700
+ hanging off it), or it asks inline. The snapshot is **run state, never the
1701
+ deliverable**, so hard rule 10 still holds; and on resume the lane re-writes
1702
+ `.current` and touches the trace file in the same step, because `/orc-grill`
1703
+ deleted the pointer at its own `FINISH`. Two traces for one document is
1704
+ correct — two lanes ran.
1705
+
1706
+ ---
1707
+
1708
+ ### v0.48.0 a document long enough to end a session, written anyway _(2026-08-13)_
1709
+
1710
+ **`/orc-doc`** writes the long document a PRD, a TSD, a cross-team
1711
+ collaboration agreement, a status report or a workflow/runbook as portable
1712
+ Markdown, and it survives the session that started it.
1713
+
1714
+ Two contracts hold the lane together, and everything else serves them:
1715
+
1716
+ > **The orchestrator never reads the document body.** It knows the document only
1717
+ > through the CLI's derived section map and through what the agents it
1718
+ > dispatched report back. **a lane that reads its own document** has broken this
1719
+ > contract.
1720
+
1721
+ > **The context is gathered once and frozen.** A resumed session reads
1722
+ > `context.md` from disk; it never re-interviews the user for what session 1
1723
+ > already settled. **a lane that re-asks a frozen question** has broken this
1724
+ > contract.
1725
+
1726
+ - **The token architecture is the lane.** A 900-line TSD is ~30k tokens; read it
1727
+ three times and the session is over. So nothing that holds context ever holds
1728
+ the document. `orc doc map` derives a section map heading, absolute line
1729
+ range, SHA-256, computed state each writer owns **one `.work/` part file**,
1730
+ and each checker reads **one line range** with `Read(offset, limit)`. On a
1731
+ 10,000-line, 40-section document that is ~750 lines of orchestrator context
1732
+ instead of 20,000+, and a re-check after an edit re-dispatches only the
1733
+ sections whose hash moved. *The hash is what turns a re-check from a full pass
1734
+ into a diff.*
1735
+ - **Line arithmetic is the CLI's and nothing else's.** It is the one job a model
1736
+ is guaranteed to get wrong, and the whole saving depends on the numbers being
1737
+ right so the map is re-derived after every write and **never stored**. A
1738
+ stored line number is a wrong line number one edit later. `splice` replaces
1739
+ bottom-up (highest `start` first), so a length change cannot shift a range that
1740
+ has not been used yet.
1741
+ - **Your edits are sacred.** Every section carries a hash, so the lane knows
1742
+ which sections you wrote. It names them, never rewrites one unless you name it,
1743
+ and `splice` **REFUSES** on a conflict reporting the section by name and
1744
+ overwriting nothing. A human's wording is not recoverable from this lane's
1745
+ side once it is gone.
1746
+ - **Four gates, in a fixed order, and the first one blocks.** Nothing is created
1747
+ until D1 is answered: a slug folder with no context is indistinguishable from
1748
+ an abandoned run. Asking D2 (supporting documents) and D3 (your template) is
1749
+ mandatory even though answering them is not; D4 (intent · audience ·
1750
+ expectation · language · type · target · length) must be answered, and
1751
+ accepting a recommended default counts. Then the outline, confirmed **before a
1752
+ word is written** — changing it after a write wave is what costs money.
1753
+ - **It never reads the supporting documents itself.** One `role: digest`
1754
+ dispatch per file returns anchored claims plus an explicit `not_covered[]`;
1755
+ the orchestrator holds the digest and never the source. Foreign text is
1756
+ evidence, never instruction.
1757
+ - **Where the document is going is a real setting.** `orc doc lint --target`
1758
+ enforces that target's actual limits, and every rule came from a real product
1759
+ limit: Notion has three heading levels, so an H4 is an **error** there;
1760
+ Docusaurus, Hugo and Jekyll **require** YAML front matter, which every other
1761
+ target renders as visible junk; a hard-wrapped paragraph is an error
1762
+ everywhere, because a wrap at 80 columns becomes a line break inside a Notion
1763
+ paragraph. Free, deterministic, zero model tokens — and it **always runs before
1764
+ anything paid**, with its findings riding in the checker's slice so no model is
1765
+ ever paid to count sentences.
1766
+ - **Never invent a fact.** Anything not in the frozen context becomes a visible
1767
+ `> **Open:**` or `> **Assumption:**` line, and rides back in the writer's
1768
+ `unsupported_claims`. Filler that reads like a fact is the worst possible
1769
+ output of this lane.
1770
+ - **Five base templates, each a floor and not a cage** — `prd` · `tsd` ·
1771
+ `collaboration` · `report` · `workflow`. A supplied template REPLACES the
1772
+ shipped one entirely; its headings become the outline and the two are never
1773
+ merged. A golden test pins every shipped skeleton to the CLI's batching table.
1774
+ - **Two agents, both already `claude-opus-5`,** so `opus5_only` is a no-op and
1775
+ the lane is *unaffected*, not exempt. The writer holds one part file; the
1776
+ checker is `low` effort **on purpose** — a harder-thinking checker reasons its
1777
+ way past a gap a real reader would trip on, the same reasoning that pins
1778
+ `/orc-challenge`'s cold reader at `low`. Nothing may upgrade it.
1779
+ - **`/orc-grill` and `/orc-brainstorm` gain a "write this up" exit**, so an
1780
+ interview's settled decisions arrive as a pre-answered D1 and D4 and the user
1781
+ only confirms. At handoff `/orc-doc` offers `/orc-challenge` in a separate
1782
+ session, which is the separation `/orc-challenge`'s own contract already
1783
+ enforces from the other side.
1784
+ - **The `orc doc` CLI family** (13 subcommands, every read `--json`, every one an
1785
+ exit-code contract), four config keys (`doc_max_lines_per_agent`,
1786
+ `doc_max_parallel` with a **hard cap of 4**, `doc_language`, `doc_dir`), and a
1787
+ **Docs panel** in `orc ui` whose ribbon draws the whole document in one
1788
+ picture — one block per section, sized by its length and coloured by its state.
1789
+ - Counts move: **skills 37 38 · commands 28 29 · agent files 44 → 46.**
1790
+
1791
+ ---
1792
+
1793
+ ### v0.47.0 the lane that refuses to produce _(2026-08-12)_
1794
+
1795
+ **Every other lane in ORC and nearly every other skill in the ecosystem —
1796
+ produces. This one refuses to.** `/orc-challenge` grades a finished artifact,
1797
+ writes down what is wrong, and then stops and makes the user go away and fix it
1798
+ somewhere else. The stopping is not friction: **the separation is the measuring
1799
+ instrument.**
1800
+
1801
+ **The one-sentence contract: ORC judges, the user fixes, ORC re-judges and ORC
1802
+ never fixes what it judged.** A session that just wrote the fix will grade its
1803
+ own homework and it will always pass. That registers as the third member of an
1804
+ existing pair — `a lane that answers its own interview question` (v0.42.0),
1805
+ `a lane that picks its own favourite` (v0.45.0), and now **`a lane that fixes
1806
+ what it judged`**. Same split every time: facts and findings are ORC's, the work
1807
+ and the decision are the user's.
1808
+
1809
+ **Rule 0 precedes every other rule: it never guesses the goal.** A finding is
1810
+ only a finding relative to a goal — the same TSD is *finished* for one purpose
1811
+ and nowhere near done for another. A lane that assumes will attack the wrong
1812
+ thing with total confidence, and every one of its findings will be *defensible*,
1813
+ which is worse than being obviously wrong: the user spends three iterations
1814
+ fixing what did not matter. So intake ASKS, in ONE round, for the goal, the
1815
+ audience, what "done" means, the template, and where the fixed version will go —
1816
+ and freezes them to `goals.md`. **`orc challenge init` has no default for
1817
+ `--goal`, `--audience` or `--done-means`**, so a run that tried to skip the round
1818
+ fails at the CLI by name instead of inventing a purpose. Every finding must name
1819
+ which goal element it `serves`; one that cannot is **dropped**, which is the
1820
+ mechanism that stops a large context window from reviewing the entire universe.
1821
+
1822
+ **Three agents, and they are three different INSTRUMENTS, not three tiers.**
1823
+
1824
+ - **`orc-challenge-reader-opus-5-low`** the cold read. Tools: `Read` and
1825
+ nothing else. It is given the artifact and the audience line, never the goal,
1826
+ and it answers questions FROM the artifact rather than reviewing it. Returns a
1827
+ scored questionnaire (`8/12`). **`low` effort is a measurement choice, not a
1828
+ cost one:** a harder-thinking reader reasons around exactly the gaps this
1829
+ exists to find, so a stronger configuration is a WORSE instrument.
1830
+ - **`orc-challenge-judge-opus-5-high`** grades against the frozen template and
1831
+ goal. Its slice is **SEALED**: paths and finding ids only, never prose from the
1832
+ session, never a diff summary, never "the user says they fixed #4". A fix is a
1833
+ claim; a verdict is evidence. **It cannot declare a pass** `orc challenge
1834
+ record` computes that, which removes leniency as a possibility.
1835
+ - **`orc-challenge-advisor-opus-5-med`** dispatched only on a FAIL (advice on a
1836
+ passed artifact is invented work and it costs money). Twelve findings are
1837
+ usually three causes: it groups them by root cause, orders them with the
1838
+ dependency reason, and flags the ones that are really unmade DECISIONS. No
1839
+ prose, no diffs handing over wording is fixing by another name.
1840
+
1841
+ All three are already `claude-opus-5`, so `opus5_only` is a no-op here: zero new
1842
+ pairs, no rename churn. The lane is **unaffected, not exempt**.
1843
+
1844
+ **`orc challenge lint` the deterministic engine, and it costs zero model
1845
+ tokens.** Structure against the frozen template (missing / out-of-order /
1846
+ invented / empty-ceremony sections, table column drift, untagged code fences,
1847
+ links and `file:line` anchors that do not resolve) plus prose (acronyms used
1848
+ before they are defined, sentences over 25 words with a p50/p90 distribution, a
1849
+ passive-voice percentage, curated idioms and phrasal verbs, ambiguous
1850
+ quantifiers, bare-pronoun openers, placeholder markers, a Flesch–Kincaid
1851
+ estimate). **Sentences are measured over PARAGRAPHS, not lines** a hard-wrapped
1852
+ 43-word sentence is still a 43-word sentence, and splitting at the newline is how
1853
+ a length check silently passes every wrapped document. Two honesty rules are
1854
+ printed by the command itself: it is a SIGNAL, not a verdict, and it is
1855
+ English-specific and heuristic. Its real payoff is that `lint.json` rides in the
1856
+ judge's slice, so the judge never spends tokens counting. It is useful with no
1857
+ cycle, no model and no ORC run at all: `orc challenge lint README.md`.
1858
+
1859
+ **Conservation nothing evaporates.** Every finding from iteration N−1 appears
1860
+ in N with exactly ONE outcome (`resolved` · `still-open` · `superseded` ·
1861
+ `withdrawn` · `accepted`) and a reason; below 100% coverage the verdict is
1862
+ malformed and `record` rejects it **naming the missing ids**. A silently dropped
1863
+ finding is indistinguishable from a fixed one, and that is the classic way a
1864
+ review cycle appears to converge. `record` also rejects an unknown carry id, a
1865
+ reasonless withdrawal, an uncited supersede, an **ignored rebuttal**, and a
1866
+ **silent dimension** — `NOT-CHECKED` with a reason is allowed, silence is not.
1867
+
1868
+ **Two escape valves, because a loop with no exit is a trap.** `orc challenge
1869
+ accept <slug> <id> "reason"`the finding stops blocking immediately and stays
1870
+ visible forever in the report with the reason; never automatic (the `/orc-pact`
1871
+ retirement rule). `orc challenge rebut <slug> <id> "reason"` the next judge
1872
+ must answer it explicitly, `withdrawn` with an admission or `upheld` with new
1873
+ evidence, and a verdict that ignores it is rejected. Without it, one wrong
1874
+ finding loops forever and the user's only move is to give up.
1875
+
1876
+ **Convergence, not a cap.** There is deliberately no loop cap and no config key
1877
+ for one: every other loop in ORC runs inside a single session and costs tokens
1878
+ per turn, but here each turn is a separate human sitting down to work, and a cap
1879
+ that refused on iteration 6 would be refusing to review a hard document. It
1880
+ reports `stalled` instead — once, with three honest options.
1881
+
1882
+ **Seven states, all COMPUTED, none stored**`AWAITING-JUDGE`, `AWAITING-FIX`,
1883
+ `AWAITING-RECHECK`, `PASSED`, `STALE-PASS` (honest, not a failure the
1884
+ `UNCHECKABLE` precedent), `MISSING-REVISION`, and `TAMPERED` (a verdict file
1885
+ changed after it was recorded: reported, never silently re-graded). Two flags
1886
+ ride alongside rather than becoming states of their own, because a state that
1887
+ means two things is a state that lies: `stalled` and `no_template`.
1888
+
1889
+ **The resumed session never asks where the fix went.** `revision_mode` is
1890
+ declared at intake and restated in a `Where to put the revised version` block in
1891
+ every fix brief; `orc challenge diff` resolves the expectation first and then
1892
+ reports which carried findings the change actually TOUCHED
1893
+ coverage-relative, the `computeWikiFreshness` lesson applied to findings, and a
1894
+ hint for the human that is **never an input to the judge**. When the declared
1895
+ path is not there, `MISSING-REVISION` **lists candidates and never adopts one**:
1896
+ picking the closest-looking file would point the judge at the wrong artifact and
1897
+ produce a page of confident, useless findings. The escape (`orc challenge expect
1898
+ --set`) is a recorded command.
1899
+
1900
+ **The CLI half: 12 subcommands, every read with an exit-code contract and
1901
+ `--json`.** `list` (0/1/3) · `status` (0/1/2/3) · `show` · `diff` (0/1/2/3) ·
1902
+ `expect` · `lint` (0/1/2) · `outline` · `record` (the GATE, not a store) ·
1903
+ `accept` · `rebut` · `template`/`goals` (re-freezing is a recorded event that
1904
+ needs a reason, and prior iterations keep their stamp) · `report` (derives
1905
+ `CHALLENGE.md`, plus the final report on a pass). `challenge.json` has exactly
1906
+ one writer, and it is never a model.
1907
+
1908
+ **The `orc ui` Challenge panel** renders it and decides nothing about it: the
1909
+ goal block above everything, the state chip with its ONE next action inline, an
1910
+ iteration timeline whose **geometry is solved from the box size** (with a dashed
1911
+ version break wherever a goal or template was re-frozen), the convergence chart
1912
+ stacked by severity, a dimension strip where `NOT-CHECKED` keeps its slot and
1913
+ carries its reason, the cold reader's score, and the findings with their accept /
1914
+ rebut buttons. **A free action gets a button, a paid action gets a copy-able
1915
+ command** — running an iteration has no write route at all. `--fixtures` carries
1916
+ one of every state including the ugly ones, and a test asserts it.
1917
+
1918
+ **Four config keys**, all `common`: `challenge_pass_severity` (default `p1`),
1919
+ `challenge_stall_after` (3), `challenge_reader` (`on`; `off` makes D4 report
1920
+ `NOT-CHECKED` with that reason, never silently), and `challenge_gate` (`warn`;
1921
+ there is deliberately no `block` — the `/orc-pact` precedent). Deliberately NOT
1922
+ added: a same-session escape hatch (that is how the premise dies), any model or
1923
+ effort key, and any loop cap.
1924
+
1925
+ **Seams:** `/orc` prints one preflight line when it is about to build from a
1926
+ document that has not passed its own review; `/orc-analyze` prints the cycle
1927
+ state at Phase A (the two compose in one order — challenge it, then analyze it);
1928
+ `/orc-pact` gains the finding-that-is-really-a-decision harvest; intake's "I
1929
+ don't know yet" suspends into `/orc-grill` and comes back; `/orc-export` can
1930
+ carry a PASSED cycle as portable evidence.
1931
+
1932
+ **Trace:** lane `challenge`, **Iterative tier** (one packet per completed
1933
+ iteration), and a new `CHALLENGE iter=…` verb whose line the CLI assembles so
1934
+ nothing composes a second wording for the same number. Several trace files for
1935
+ one cycle is CORRECT — several sessions ran.
1936
+
1937
+ ### v0.46.1 — see a lane run before you pay for one _(2026-08-12)_
1938
+
1939
+ **The docs answered "what is ORC" four times and never answered "what does a
1940
+ lane look like when it runs".** Rides on top of v0.46.0, below.
1941
+
1942
+ **`mock-run/`one written walkthrough per lane.** What you type, what ORC
1943
+ prints back, what lands on disk, in easy English, all on one shared example
1944
+ project. Nothing was executed to make them: they exist so nobody has to spend
1945
+ tokens to find out what a command does. Start at `mock-run/INDEX.md`.
1946
+
1947
+ **`orc mock-run list | show <slug>`** reads the same catalogue from the
1948
+ terminal, and **`orc ui` grows a Mocked Skill Use panel** every walkthrough,
1949
+ grouped, searchable, with a reading pane. The catalogue is DERIVED from the
1950
+ files on disk (title from the heading, lane from whether the command really
1951
+ exists), so adding a walkthrough needs no list edited anywhere; the panel
1952
+ renders it and decides nothing about it, exactly like the Flow stepper.
1953
+
1954
+ **The README is 928 lines shorter and current.** It was still describing an
1955
+ older payload — the six v0.46.0 lanes were missing from the panel list, the
1956
+ config table showed 11 of 52 keys, and the eval section quoted a round from four
1957
+ releases ago. History moved here to `CHANGELOG.md`, which is now what `orc
1958
+ changelog` fetches: a README carrying one entry would have answered a user ten
1959
+ releases behind with a single line. The detail that used to bloat it lives in
1960
+ `guides/configuration.md` and `guides/model-selection.md`.
1961
+
1962
+ **Two real bugs found while building it.** The panel's markdown renderer looped
1963
+ forever on a malformed table row (the paragraph branch is the fall-through, so a
1964
+ line every branch declined never advanced the cursor), and an upgrade modal
1965
+ showed the newest release with `## Earlier releases` glued to the end of it —
1966
+ an entry now stops at the next section heading, not just at the next release.
1967
+
1968
+ ---
1969
+
1970
+ ### v0.46.0 — a lane that remembers, a lane that declines, and a lane that measures _(2026-08-10)_
1971
+
1972
+ **The ecosystem has a thousand skills that GENERATE.** This release builds the
1973
+ three things a generator structurally cannot be, plus the wiki work that pays for
1974
+ them and the panels that make them visible. Six new lanes, one new agent, and the
1975
+ biggest cost cut available to ORC so far.
1976
+
1977
+ **`/orc-pact` — the lane that remembers.** `/orc-grill` and `/orc-brainstorm`
1978
+ already settle constraints, and a plan already carries them into every executor
1979
+ slice. Then the run ends and they evaporate. The pact is a ledger that outlives
1980
+ the run, with four states that are **computed on read, never stored**: HOLDING,
1981
+ **DRIFTED** (commits since it was verified touched the files it anchors —
1982
+ coverage-relative, so a promise about payments does not fall into doubt because
1983
+ the README changed), **UNCHECKABLE** (nothing cheap proves it — the honest state,
1984
+ and it never counts against you), and BROKEN. It never invents a promise: every
1985
+ entry records where it came from. It never retires one for you. And the payoff is
1986
+ automaticat planning time, a drifted promise whose files your plan is about to
1987
+ touch is injected into the planner as a constraint, so last month's decision
1988
+ constrains this month's work. `PACT.md` is a committed, PM-readable file at your
1989
+ project root, rendered by the CLI from the ledger so the two can never disagree.
1990
+
1991
+ **`/orc-boundary` — the lane that declines.** Every skill you can install assumes
1992
+ the answer to *"should the agent do this?"* is yes; agents spend 5×–50× longer
1993
+ than human experts on a task, and most of the excess goes into attempts that were
1994
+ never going to succeed. Three verdicts per area EXECUTE, ESCALATE, REFUSE each
1995
+ derived from four questions answered from things already on disk: can it verify
1996
+ itself, does it know this area, is the change reversible, is this a decision
1997
+ rather than a fact. **A REFUSE always names what would make it a yes** — "no" with
1998
+ no "unless" is a shrug, so a refusal with no checklist is treated as a malformed
1999
+ card. It gates ORC's own dispatch, never you: `boundary_gate: block` lifts a
2000
+ refused task out of its wave and **the wave still runs the rest**.
2001
+
2002
+ **`/orc-handoff` — the first ORC lane for someone who does not read code.** The
2003
+ insight nobody shipped: the safety grade does not come from the file type, it
2004
+ comes from **whether a cheap check exists**. A settings file with a validator is
2005
+ green; the same file without one is amber. It maps every surface a PM or designer
2006
+ can own, and changing one is five steps with the **undo command shown before the
2007
+ write**, the check run afterwards and reported in plain words, and a red surface
2008
+ never touched at all. Every file in that lane is written in simple English.
2009
+
2010
+ **`/orc-budget`what a run costs, in the unit you are billed in.** Not a dollar
2011
+ figure: on Pro or Max you burn a 5-hour window, not an invoice. The forecast's
2012
+ core object is a **token vector** fresh input, cache write, cache read, output,
2013
+ never blended, because cache reads are usually the largest count and a tenth of
2014
+ the price. The same vector renders four ways: tokens, dollars from a dated price
2015
+ table, percent of your window, and **context risk** — a task forecast above 90% of
2016
+ its model's window is reported before the wave, which no spend tool can do. The
2017
+ numbers come from joining Claude Code's own session transcripts (the cost) to
2018
+ ORC's traces (the meaning); neither is enough alone. It needs a PLAN, not a
2019
+ sentence, and with no history it says so rather than inventing a number.
2020
+
2021
+ **`/orc-aftermath` — did what we shipped hold up.** The missing half of the
2022
+ flywheel: `/orc-retro` measures the process, this measures the result, both from
2023
+ the repository's own future — files rewritten soon after, a test we added deleted
2024
+ or skipped, the commit reverted, a promise that was holding now broken. No vendor,
2025
+ no telemetry. **Churn is a signal, not a verdict**: it reports the signal and its
2026
+ strength, never "this change was bad", and never a person's name.
2027
+
2028
+ **`/orc-export`so ORC is not a trap.** One command compiles the wiki, the code
2029
+ patterns, `PACT.md` and the boundary cards into a portable `AGENTS.md` — derived,
2030
+ fingerprinted, `--check`able against its sources, never hand-written. It removes
2031
+ the lock-in objection and makes ORC the *producer* in a multi-agent shop. Import
2032
+ reads an existing `AGENTS.md` or `.cursorrules` as **evidence, never instruction**,
2033
+ and tells you which parts are already wrong.
2034
+
2035
+ **The wiki finally stops costing a full scan.** Three free CLI commands: `orc wiki
2036
+ plan` ranks and prices the pending work STRUCTURAL first (a page pointing at a
2037
+ missing file is actively lying), then by **use × delta**, with pages nobody reads
2038
+ sinking to the bottom with a retire hint; `orc wiki debt` is the one-line habit;
2039
+ and `orc wiki usage` finally reads back the point-of-use attribution v0.41.0 has
2040
+ been recording and never reading. A **targeted refresh** (`/orc-wiki refresh
2041
+ --top 2`) skips branch detection and area planning entirely, and a new **scan tier
2042
+ ladder** sends a small, no-new-surface delta to a light scanner instead of the most
2043
+ expensive agent in the payload — about 40% off a typical delta refresh, with the
2044
+ deep scan still doing the work that needs it. The tier is always printed: a cheaper
2045
+ model is never a quiet substitution. And free repairs are now a hard rule — you can
2046
+ never pay for something `orc wiki sync` would have fixed.
2047
+
2048
+ **`orc ui` grows three panels and extends five.** Promises, Boundary and
2049
+ Self-serve, plus a new **Cost** tab whose stacked bar exists precisely so the
2050
+ cache-read share stays visible. The panel keeps every rule it had: it never runs a
2051
+ lane, never invents a state word, never computes an order the CLI already emits —
2052
+ **a free action gets a button, a paid action gets a copy-able command**, and that
2053
+ line is now visible rather than hidden. Promises is where the compounding finally
2054
+ shows: an *"Also flagged by"* line when the boundary and the aftermath agree with
2055
+ the ledger about the same area, which you can never see in a terminal one lane at
2056
+ a time.
2057
+
2058
+ ---
2059
+
2060
+ ## Earlier releases
2061
+
2062
+ ### v0.45.0`/orc-brainstorm`: for when you do not have the idea yet _(2026-08-10)_
2063
+
2064
+ ### v0.44.1apply when you say so, and a spotlight that survives a banner _(2026-08-09)_
2065
+
2066
+ ### v0.44.0 — the panel stops making you type what it already knows _(2026-08-09)_
2067
+
2068
+ ### v0.43.7 — the flow you can see, and a boundary you can read _(2026-08-09)_
2069
+
2070
+ ### v0.43.6 — `orc ui` in two languages, and panels that point at the right page _(2026-08-08)_
2071
+
2072
+ ### v0.43.5 — the update check works, and the UI teaches itself _(2026-08-08)_
2073
+
2074
+ ### v0.43.4 — a warning that finally clears, an Experiment panel, crosslink from the UI _(2026-08-08)_
2075
+
2076
+ ### v0.43.3 — `orc ui`: it tells you about updates, and 36 keys stop being a wall _(2026-08-08)_
2077
+
2078
+ ### v0.43.2 — `orc ui`: boxes stop colliding, because the container owns the gap _(2026-08-08)_
2079
+
2080
+ ### v0.43.1 — the panel's stylesheet and script actually reach the browser _(2026-08-08)_
2081
+
2082
+ ### v0.43.0 — `orc ui`: a control panel for everything that is not ai _(2026-08-08)_
2083
+
2084
+ ### v0.42.0 — Say what you mean, see what it costs, find your way back _(2026-08-08)_
2085
+
2086
+ ### v0.41.0 — A wiki that can tell you it is fresh, and TDD only where it can fail _(2026-08-06)_
2087
+
2088
+ ### v0.40.0 — Gotchas: repair memory that outlives the run _(2026-08-06)_
2089
+
2090
+ ### v0.39.0 — The read ladder, and foreign input that is evidence rather than instruction _(2026-08-06)_
2091
+
2092
+ ### v0.38.1 — `orc doctor --json` + handoff carry-over that says what is re-derived _(2026-08-06)_
2093
+
2094
+ ### v0.38.0 — `/orc-quick`: the quick lane, and the gate no config can collapse _(2026-08-05)_
2095
+
2096
+ ### v0.37.0 — Stacked pull requests: a measured ship gate + two standalone lanes _(2026-08-03)_
2097
+
2098
+ ### v0.36.0 — `opus5_only`: one model for every role, not just executors _(2026-08-02)_
2099
+
2100
+ ### v0.35.0 — `opus5_executor_only`: one model, effort as the cost dial _(2026-08-02)_
2101
+
2102
+ ### v0.34.8 — `orc pattern status` rejects a language key the payload has never heard of _(2026-08-01)_
2103
+
2104
+ ### v0.34.7 — DIY: a usable status contract, and compile docs that match the compiler _(2026-08-01)_
2105
+
2106
+ ### v0.34.6 — Analyze: the evidence gate now covers the rows a good analysis produces _(2026-08-01)_
2107
+
2108
+ ### v0.34.5 — Wiki: stop losing tags silently, let a delta clear its own delta _(2026-08-01)_
2109
+
2110
+ ### v0.34.4 — Planner: scorable facets, and TDD rules scoped to reality _(2026-08-01)_
2111
+
2112
+ ### v0.34.3 — Slice boundary: the worktree, not the editor _(2026-08-01)_
2113
+
2114
+ ### v0.34.2 — Trace subsystem: the pointer clobber, and a writer contract that holds _(2026-08-01)_
2115
+
2116
+ ### v0.34.1 — Install integrity: run state survives `orc update` _(2026-08-01)_
2117
+
2118
+ ### v0.34.0 — Opus 5: top scoring band, every core role, medium-effort session tier _(2026-07-25)_
2119
+
2120
+ ### v0.33.0 — Knowledge deepening + verification revamp _(2026-07-25)_
2121
+
2122
+ ### v0.32.0 — Trace revamp: narration is dispatched, not remembered _(2026-07-24)_
2123
+
2124
+ ### v0.31.0 — Execution-integrity revamp: plan handoff, attributable traces, facet scoring _(2026-07-23)_
2125
+
2126
+ ### v0.30.0 — Scoring revamp, Fable 5 role override, tier-aware guards, `orc onboarding` _(2026-07-23)_
2127
+
2128
+ ### v0.29.0 — Drift-prevention hardening: install manifest + prune, `orc doctor`, a real test suite _(2026-07-22)_
2129
+
2130
+ ### v0.28.1 — Defect fixes: package encoding, trace event routing, count/doc drift _(2026-07-22)_
2131
+
2132
+ ### v0.28.0 — Run integrity: rich full-lane traces, deterministic wave stop, visible knowledge gates _(2026-07-21)_
2133
+
2134
+ ### v0.27.0 — `/orc-poly`: plan one change across two-or-more repos without drift _(2026-07-20)_
2135
+
2136
+ ### v0.26.0 — Test-gen output pinned to a visible `test-generator/<change-slug>/` deliverable _(2026-07-19)_
2137
+
2138
+ ### v0.25.1 — Eval report: the full 17-lane suite graded against the v0.25.0 payload _(2026-07-18)_
2139
+
2140
+ ### v0.25.0 — Deterministic artifact detection: a generated wiki/pattern is never missed _(2026-07-18)_
2141
+
2142
+ ### v0.24.0 — Crosslink fused into wiki generation: always-on, per-scan-task, never wiped _(2026-07-18)_
2143
+
2144
+ ### v0.23.0 — Trace fix: SPAWN restored on the `Agent` tool, stale runs rotate to fresh files _(2026-07-18)_
2145
+
2146
+ ### v0.22.0 — `/orc-learn`: per-feature onboarding docs — learning.md + knowledge.md, wiki-deep, git-ignored _(2026-07-17)_
2147
+
2148
+ ### v0.21.0 — Statusline shows live subscription usage: 5h ↔ weekly, official numbers _(2026-07-16)_
2149
+
2150
+ ### v0.20.0 — One source of truth: generated executor agents + shared cross-lane contracts _(2026-07-16)_
2151
+
2152
+ ### v0.19.0 — Thin spines: skill compaction, budget lint, and a trace that logs every phase _(2026-07-16)_
2153
+
2154
+ ### v0.18.0 — `orc wiki sync`: the wiki registers itself — a paused scan is no longer an invisible wiki _(2026-07-15)_
2155
+
2156
+ ### v0.17.3 — Trace the wiki consult: Phase 1 now logs whether the run grounded in the wiki (and if it was stale) _(2026-07-14)_
2157
+
2158
+ ### v0.17.2 — Behavior-trace logging is permanent + the trace folder is now created deterministically _(2026-07-14)_
2159
+
2160
+ ### v0.17.1 — Complete cross-repo crosslink setup guide in the orc-wiki README _(2026-07-14)_
2161
+
2162
+ ### v0.17.0 — `orc crosslink`: cross-repo wiki references — advisory boundary contracts _(2026-07-14)_
2163
+
2164
+ ### v0.16.1 — Interactive `orc diy` composer + numbered picks in `orc config` _(2026-07-14)_
2165
+
2166
+ ### v0.16.0 — `/orc-diy`: build your own lane — CLI-composed flow, compiled, hard-gated _(2026-07-14)_
2167
+
2168
+ ### v0.15.0 — Wiki v2: evidence-anchored docs · per-file staleness registry · integrity gate _(2026-07-14)_
2169
+
2170
+ ### v0.14.0 — Postgres data-access playbook: cross-cutting query grounding _(2026-07-13)_
2171
+
2172
+ ### v0.13.0 — `/orc-claude`: local CLAUDE.md builder — fenced sections, fingerprint refresh, zero questions _(2026-07-12)_
2173
+
2174
+ ### v0.12.0 — Lossless context-combiner: conservation gate · overlap taxonomy · evidence freshness _(2026-07-12)_
2175
+
2176
+ ### v0.11.0 — `/orc-fast`: knowledge-gated speed lane + wiki freshness infrastructure _(2026-07-12)_
2177
+
2178
+ ### v0.10.1 — README: a fuller "Why ORC exists" _(2026-07-12)_
2179
+
2180
+ ### v0.10.0 — `/orc-ultra`: max-effort advisor + three judgment gates for ultra-complex work _(2026-07-12)_
2181
+
2182
+ ### v0.9.0 — Trust-but-verify the analyst→planner chain: quote-anchored evidence · coverage gate · anchored judgment _(2026-07-12)_
2183
+
2184
+ ### v0.8.1 — /orc-retro delivers upstream: PR/issue to the ORC repo, channel-gated _(2026-07-12)_
2185
+
2186
+ ### v0.8.0 — Close the loop: grounded intake · scoring anchors · OUTCOME marker · /orc-retro trace miner · eval harness _(2026-07-12)_
2187
+
2188
+ ### v0.7.0 — Evidence everywhere: grounded plans · verbatim proof · anchored findings · contract lint · trace fixes _(2026-07-12)_
2189
+
2190
+ ### v0.6.0 — P0–P3 ladder · house rules · deep playbooks + wired gates · 3 new languages · FE rule packs · security pass _(2026-07-11)_
2191
+
2192
+ ### v0.5.1 — Statusline false-degrade fix _(2026-07-11)_
2193
+
2194
+ ### v0.5.0 — Code-pattern findings: executors match your house style, invariants always enforced
2195
+
2196
+ ### v0.4.5 — Rewrite weak worker descriptions (the real score lever)
2197
+
2198
+ ### v0.4.4 — Act on external review: raise sub-70 workers, fix cross-spine paths
2199
+
2200
+ ### v0.4.3 — `orc-analyze`: trim description under the 1024-char skill-spec limit
2201
+
2202
+ ### v0.4.2 — External-review pass: worked examples + sharper mini-analyst activation
2203
+
2204
+ ### v0.4.1 — `orc-mini`: faster, safer fast-lane — smoke gate, opt-in tests, trimmed ceremony
2205
+
2206
+ ### v0.4.0 — Opt-in Phase 6.5 Test Authoring (writes test cases, never runs them)
2207
+
2208
+ ### v0.3.0 — Opt-in behavior-trace logging + claimed-vs-actual model verification
2209
+
2210
+ ### v0.2.4 — `orc-analyze`: gather anchored adjacent-scope context (non-actionable)
2211
+
2212
+ ### v0.2.3 — Context Combiner: merge 2+ related analyses into one combined spec
2213
+
2214
+ ### v0.2.2 — Config: enforce per-key override-first resolution
2215
+
2216
+ ### v0.2.1 — Move config editing into the `orc config` CLI (zero-token); drop `/orc-config`
2217
+
2218
+ ### v0.2.0 — Doc-optional evidence-backed analyst + deep mode