@azure-id/orc 1.9.0 → 1.9.2

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.
Files changed (134) hide show
  1. package/CHANGELOG.md +202 -0
  2. package/README-id.md +57 -59
  3. package/README.md +53 -54
  4. package/bin/build-agents.js +109 -109
  5. package/bin/cli.js +262 -58
  6. package/bin/graph-audit.js +235 -0
  7. package/bin/graph-extract.js +308 -3
  8. package/bin/graph-gain.js +23 -3
  9. package/bin/graph-map.js +9 -1
  10. package/bin/graph-query.js +152 -10
  11. package/bin/graph-shard.js +6 -1
  12. package/bin/graph-signals.js +287 -4
  13. package/bin/graph.js +717 -658
  14. package/bin/onboarding-content.js +4 -4
  15. package/bin/pricing.json +207 -200
  16. package/bin/verify-contracts.js +117 -2
  17. package/bin/verify-package.js +11 -7
  18. package/bin/webui/css/04-motion.css +162 -152
  19. package/bin/webui/css/panels/knowledge.css +563 -116
  20. package/bin/webui/fixtures/extra.js +2036 -2036
  21. package/bin/webui/fixtures/hookui.js +5 -5
  22. package/bin/webui/fixtures/knowledge.js +21 -4
  23. package/bin/webui/fixtures/settings.js +305 -305
  24. package/bin/webui/i18n/en/knowledge.json +122 -4
  25. package/bin/webui/i18n/id/knowledge.json +122 -4
  26. package/bin/webui/js/panels/knowledge.js +573 -9
  27. package/bin/webui/js/panels/overview.js +13 -4
  28. package/mock-run/context-combiner.md +100 -100
  29. package/mock-run/orc-budget.md +534 -534
  30. package/mock-run/orc-challenge-council.md +262 -262
  31. package/mock-run/orc-ultra.md +103 -103
  32. package/package.json +1 -1
  33. package/templates/agents/MODEL-MAPPING.md +43 -43
  34. package/templates/agents/orc-advisor-opus-5-xhigh.md +56 -56
  35. package/templates/agents/orc-analyze-mini-opus-5-med.md +60 -60
  36. package/templates/agents/orc-analyze-mini-sonnet-5-high.md +58 -58
  37. package/templates/agents/orc-challenge-advisor-opus-5-med.md +75 -75
  38. package/templates/agents/orc-challenge-contrarian-opus-5-high.md +110 -110
  39. package/templates/agents/orc-challenge-executor-opus-5-med.md +114 -114
  40. package/templates/agents/orc-challenge-expansionist-opus-5-med.md +112 -112
  41. package/templates/agents/orc-challenge-judge-opus-5-high.md +132 -132
  42. package/templates/agents/orc-challenge-outsider-opus-5-low.md +109 -109
  43. package/templates/agents/orc-challenge-principles-opus-5-high.md +109 -109
  44. package/templates/agents/orc-challenge-reader-opus-5-low.md +90 -90
  45. package/templates/agents/orc-claude-writer-opus-5-med.md +55 -55
  46. package/templates/agents/orc-context-combiner-opus-5-high.md +88 -88
  47. package/templates/agents/orc-doc-checker-opus-5-low.md +108 -108
  48. package/templates/agents/orc-doc-writer-opus-5-med.md +134 -134
  49. package/templates/agents/orc-executor-haiku-4-5.md +2 -1
  50. package/templates/agents/orc-executor-opus-4-7-high.md +2 -1
  51. package/templates/agents/orc-executor-opus-4-7-med.md +2 -1
  52. package/templates/agents/orc-executor-opus-4-8-high.md +2 -1
  53. package/templates/agents/orc-executor-opus-5-high.md +4 -3
  54. package/templates/agents/orc-executor-opus-5-low.md +4 -3
  55. package/templates/agents/orc-executor-opus-5-med.md +4 -3
  56. package/templates/agents/orc-executor-sonnet-4-6-high.md +2 -1
  57. package/templates/agents/orc-executor-sonnet-4-6-med.md +2 -1
  58. package/templates/agents/orc-executor-sonnet-5-high.md +2 -1
  59. package/templates/agents/orc-graph-noter-sonnet-4-6-med.md +1 -1
  60. package/templates/agents/orc-judge-opus-5-xhigh.md +85 -85
  61. package/templates/agents/orc-learn-writer-opus-5-low.md +73 -73
  62. package/templates/agents/orc-pattern-codifier-opus-5-med.md +65 -65
  63. package/templates/agents/orc-planner-mini-opus-5-med.md +4 -4
  64. package/templates/agents/orc-planner-mini-sonnet-5-high.md +1 -1
  65. package/templates/agents/orc-planner-opus-5-med.md +160 -160
  66. package/templates/agents/orc-recon-opus-5-low.md +18 -8
  67. package/templates/agents/orc-recon-sonnet-4-6-med.md +15 -5
  68. package/templates/agents/orc-retro-opus-5-med.md +3 -3
  69. package/templates/agents/orc-reviewer-opus-5-med.md +60 -60
  70. package/templates/agents/orc-scout-opus-5-low.md +40 -40
  71. package/templates/agents/orc-system-analyst-opus-5-high.md +120 -120
  72. package/templates/agents/orc-test-author-opus-5-med.md +71 -71
  73. package/templates/agents/orc-test-designer-opus-5-high.md +158 -158
  74. package/templates/agents/orc-test-interpreter-opus-5-low.md +130 -130
  75. package/templates/agents/orc-verifier-opus-5-med.md +69 -69
  76. package/templates/agents/orc-wiki-scanner-opus-5-med.md +81 -81
  77. package/templates/commands/orc-ultra.md +17 -17
  78. package/templates/commands/orc-verify.md +11 -11
  79. package/templates/hooks/README.md +13 -3
  80. package/templates/hooks/orc-effort-guard.js +178 -178
  81. package/templates/hooks/orc-graph-hook.js +53 -7
  82. package/templates/hooks/orc-statusline.js +6 -6
  83. package/templates/skills/_shared/code-graph.md +57 -18
  84. package/templates/skills/_shared/config-precedence.md +198 -198
  85. package/templates/skills/_shared/extra-dispatch.md +1346 -1346
  86. package/templates/skills/_shared/opus5-only.md +8 -8
  87. package/templates/skills/_shared/phases/analyst-gates.md +136 -136
  88. package/templates/skills/_shared/phases/execution.md +4 -4
  89. package/templates/skills/_shared/phases/planning.md +3 -3
  90. package/templates/skills/_shared/phases/preflight.md +1 -1
  91. package/templates/skills/_shared/phases/review.md +4 -2
  92. package/templates/skills/_shared/phases/ship.md +1 -1
  93. package/templates/skills/_shared/phases/trace.md +3 -2
  94. package/templates/skills/_shared/read-ladder.md +14 -1
  95. package/templates/skills/_shared/return-validation.md +1 -1
  96. package/templates/skills/context-combiner/SKILL.md +1 -1
  97. package/templates/skills/context-combiner/schemas/combined-report.md +78 -78
  98. package/templates/skills/orc/README.md +2 -2
  99. package/templates/skills/orc/SKILL.md +8 -8
  100. package/templates/skills/orc/config.md +9 -9
  101. package/templates/skills/orc/examples/full-run-mock.md +73 -73
  102. package/templates/skills/orc/references/effort-and-mode.md +222 -222
  103. package/templates/skills/orc/references/preflight-report.md +2 -2
  104. package/templates/skills/orc/references/ultra-mode.md +3 -3
  105. package/templates/skills/orc/subskills/orc-planner/SKILL.md +2 -2
  106. package/templates/skills/orc/subskills/orc-planner-mini/SKILL.md +121 -121
  107. package/templates/skills/orc/subskills/orc-review-verify/SKILL.md +76 -76
  108. package/templates/skills/orc/subskills/orc-testgen/SKILL.md +45 -45
  109. package/templates/skills/orc-analyze/SKILL.md +2 -2
  110. package/templates/skills/orc-analyze/examples/analyze-mock.md +42 -42
  111. package/templates/skills/orc-analyze/schemas/report-audit.md +83 -83
  112. package/templates/skills/orc-analyze/schemas/report-prose.md +63 -63
  113. package/templates/skills/orc-analyze/schemas/report-requirement.md +78 -78
  114. package/templates/skills/orc-challenge/README.md +142 -142
  115. package/templates/skills/orc-challenge/examples/council-full-roster.md +273 -273
  116. package/templates/skills/orc-challenge/references/council.md +315 -315
  117. package/templates/skills/orc-challenge/references/intake.md +171 -171
  118. package/templates/skills/orc-claude/SKILL.md +14 -14
  119. package/templates/skills/orc-diy/README.md +143 -143
  120. package/templates/skills/orc-diy/references/flow-schema.md +1 -1
  121. package/templates/skills/orc-doc/README.md +229 -229
  122. package/templates/skills/orc-doc/examples/orc-doc-prd-run.md +325 -325
  123. package/templates/skills/orc-doc/references/chunking.md +527 -527
  124. package/templates/skills/orc-fast/SKILL.md +4 -4
  125. package/templates/skills/orc-learn/SKILL.md +14 -14
  126. package/templates/skills/orc-learn/examples/learn-run-mock.md +61 -61
  127. package/templates/skills/orc-mini/SKILL.md +16 -20
  128. package/templates/skills/orc-mini/references/complexity.md +25 -11
  129. package/templates/skills/orc-quick/SKILL.md +12 -13
  130. package/templates/skills/orc-quick/references/gh-mode.md +1 -1
  131. package/templates/skills/orc-quick/references/look.md +5 -5
  132. package/templates/skills/orc-verify/SKILL.md +15 -15
  133. package/templates/skills/orc-verify/examples/verify-mock.md +33 -33
  134. package/templates/skills/orc-wiki/references/extra.md +1 -1
@@ -1,315 +1,315 @@
1
- # The council
2
-
3
- > **A lens raises; only the judge resolves. ORC proposes the council; the user
4
- > picks it.**
5
-
6
- **a lane that picks its own council has broken this contract.**
7
-
8
- That is the fourth member of a family, and the split is the same every time —
9
- the facts are ORC's to look up, the decision is the user's to take:
10
-
11
- | Lane | Broken by |
12
- |---|---|
13
- | `../../_shared/interview.md` | `a lane that answers its own interview question` |
14
- | `/orc-brainstorm` | `a lane that picks its own favourite` |
15
- | `/orc-challenge` | `a lane that fixes what it judged` |
16
- | `/orc-doc` | `a lane that reads its own document` |
17
- | **`/orc-challenge` council** | **`a lane that picks its own council`** |
18
-
19
- A council chosen by ORC is ORC deciding **which kinds of criticism the user is
20
- allowed to hear** — a bigger decision than any single finding in the run.
21
-
22
- ---
23
-
24
- ## The roster — seven lenses
25
-
26
- One always runs. Six are selectable. **The user selects them.**
27
-
28
- | Lens | Display | Agent | Effort | Class | Ids | Blocks? |
29
- |---|---|---|---|---|---|---|
30
- | `judge` | The Judge | `orc-challenge-judge-opus-5-high` | high | finding | `F-` | yes |
31
- | `reader` | The Cold Reader | `orc-challenge-reader-opus-5-low` | low | finding | `R-` | yes |
32
- | `contrarian` | The Contrarian | `orc-challenge-contrarian-opus-5-high` | high | finding | `C-` | yes |
33
- | `outsider` | The Outsider | `orc-challenge-outsider-opus-5-low` | low | finding | `O-` | yes |
34
- | `executor` | The Executor | `orc-challenge-executor-opus-5-med` | medium | finding | `E-` | yes |
35
- | `principles` | The First Principles Thinker | `orc-challenge-principles-opus-5-high` | high | **premise** | `Q-` | **never** |
36
- | `expansionist` | The Expansionist | `orc-challenge-expansionist-opus-5-med` | medium | **opportunity** | `X-` | **never** |
37
-
38
- `orc-challenge-advisor-opus-5-med` is **not a lens.** It never inspects the
39
- artifact for defects; it turns a FAIL into a fix strategy, and rule 5 still
40
- holds: **no advisor on PASS.**
41
-
42
- **Never hand-list these anywhere else.** `orc challenge roles --json` is the
43
- catalogue; the P0 ask in `intake.md` renders it, and `orc ui` draws the roster
44
- card from it. One list, three renderers — the Flow-stepper rule.
45
-
46
- ### What each one is for, and how each one fails
47
-
48
- | Role | It asks | It fails when |
49
- |---|---|---|
50
- | The Contrarian | "where is the fatal flaw?" | it assumes the artifact is fine and stops looking |
51
- | The First Principles Thinker | "are we even solving the right problem?" | it accepts the framing it was handed |
52
- | The Expansionist | "what is being undervalued here?" | it only counts what is wrong |
53
- | The Outsider | "what does this assume I already know?" | it is an expert and cannot un-know things |
54
- | The Executor | "what do you actually do on Monday morning?" | it grades the theory and never the first step |
55
-
56
- ### Why each effort — and the rule that protects it
57
-
58
- **Effort here is a measurement choice, not a cost choice.** The same sentence
59
- governs the cold reader and the `/orc-doc` checker, and it now governs two more:
60
-
61
- - **`outsider` is `low` for the same reason `reader` is.** A harder-thinking
62
- outsider reasons its way *around* an unexplained acronym and reports that the
63
- document is fine. The whole instrument is "do not reconstruct — report what is
64
- actually on the page." **Nothing may ever upgrade it.**
65
- - **`contrarian` is `high` because a shallow contrarian finds only the obvious.**
66
- At low effort it returns the same three surface complaints the free lint
67
- already caught.
68
- - **`principles` is `high`** — rebuilding a problem statement from the ground up
69
- is the deepest reasoning any role in this lane does.
70
- - **`expansionist` and `executor` are `medium`** — pattern work against a
71
- concrete artifact, the same class as the advisor.
72
-
73
- All seven are `claude-opus-5`, so **`opus5_only` is a no-op for this lane: it is
74
- unaffected, not exempt.** The agent count rises by exactly five, with no paired
75
- variants (the v0.47.0 precedent).
76
-
77
- ---
78
-
79
- ## The reader / outsider seam — read this before touching either
80
-
81
- These two are the closest pair in ORC, and the one place this design can produce
82
- a duplicate instrument. The distinction is **structural, not stylistic**:
83
-
84
- | | `reader` | `outsider` |
85
- |---|---|---|
86
- | Told the audience | **yes** | **no** |
87
- | Told the goal / kind / template | no | no |
88
- | What it generates | 8–15 questions **the artifact promised to answer**, from its own headings | nothing — it reacts to what is in front of it |
89
- | What it returns | a **scored** questionnaire (`8/12`) + `R-###` | an **unscored** ranked list of assumed knowledge + `O-###` |
90
- | The measurement | *can this be answered from the page?* | *what does this page assume you already know?* |
91
- | Feeds | D4 | D5, and D4 where an assumption is load-bearing |
92
-
93
- They are dispatched **with no knowledge of each other**, and their reports are
94
- never merged before the judge reads them. **Where they agree, that is the
95
- strongest comprehension evidence this lane can produce** — recorded as
96
- `corroborated_by: [reader, outsider]`, and **never an automatic severity bump**
97
- (the `/orc-aftermath` rule: churn is a signal, not a verdict).
98
-
99
- ---
100
-
101
- ## Three output classes — the honest split
102
-
103
- ```
104
- class: finding → judge, reader, contrarian, outsider, executor
105
- class: opportunity → expansionist
106
- class: premise → principles
107
- ```
108
-
109
- Two of the six cannot produce a finding **without lying**, and forcing them to
110
- would be the single worst decision available here.
111
-
112
- ### Why the expansionist cannot produce a finding
113
-
114
- A finding must carry `serves` — the goal element it advances — and `record`
115
- DROPS a finding without one (rule 0, structural). The expansionist's brief is
116
- *"what upside is everyone missing?"*, which by construction is **not** in the
117
- stated goal. Given a `serves` field it would either invent a goal element or be
118
- silently dropped by the CLI.
119
-
120
- ```yaml
121
- opportunity:
122
- id: X-002
123
- what: "the retry table generalises to every idempotent write in the service"
124
- upside: "…"
125
- first_step: "…" # concrete; an upside with no first step is a daydream
126
- anchor: "docs/tsd-payments.md:212"
127
- confidence: medium
128
- route: brainstorm # brainstorm | pact | grill | none
129
- ```
130
-
131
- **An opportunity never blocks, never has a severity, and never enters
132
- `findings[]`.** It is conserved — `orc challenge opportunity <slug> <id>
133
- --take|--drop --reason "…"`, both requiring a reason — and it is ROUTED: an
134
- adopted one belongs in `/orc-brainstorm`, and one the user wants to commit to
135
- belongs in `/orc-pact`. **This lane never builds it.**
136
-
137
- ### Why the first-principles thinker cannot produce a finding
138
-
139
- Its most valuable output is *"you are asking the wrong question entirely"* — and
140
- in this lane the question is the **frozen goal**. A finding is measured against
141
- the goal; a premise challenge disputes the **yardstick**. Those cannot be the
142
- same object.
143
-
144
- ```yaml
145
- premise:
146
- id: Q-001
147
- disputes: goal # goal | audience | done_means | out_of_scope
148
- quote: "<the exact line from goals.md it disputes>"
149
- reframe: "…" # the problem restated from the ground up
150
- what_changes: "…" # what this review would attack instead
151
- cheapest_test: "…" # how to settle it without a rewrite
152
- ```
153
-
154
- **A premise challenge is resolved by a HUMAN and by nobody else.** Exactly two
155
- resolutions exist:
156
-
157
- 1. **Adopt** → `orc challenge goals <slug> --set <path> --reason "…"` — a
158
- `regoal` event; `goals.version` increments, prior iterations keep their stamp,
159
- and the iteration rail draws the version break. That mechanism has existed
160
- since v0.47.0; the council is the first thing that can legitimately move it.
161
- 2. **Dismiss** → `orc challenge premise <slug> <id> --dismiss --reason "…"`. The
162
- reason is mandatory and stays visible in the report forever.
163
-
164
- **The judge NEVER sees the premise report.** Handing a judge a document arguing
165
- that the frozen goal is wrong biases every finding it produces afterwards.
166
-
167
- > **The three finding lenses feed the judge. The two non-finding lenses feed the
168
- > user.** That sentence is the whole architecture.
169
-
170
- ---
171
-
172
- ## C3 — dispatch discipline
173
-
174
- The **judge slice is SEALED** as it always was — one row per FINDING lens, and
175
- `principles.md` / `expansionist.md` are named as forbidden in `sealed-slice.md`.
176
-
177
- - Every lens is dispatched **BY NAME**. An unnamed dispatch cannot enforce the
178
- pin and is invisible to the trace hook (the v0.34.5 wiki-scanner lesson) — and
179
- a by-name dispatch gets `SPAWN`/`RETURN` for free, which is how `/orc-retro`
180
- can finally answer *"is the contrarian earning its dispatch?"*
181
- - **Hard cap: 3 in flight**, announced when it bites, **no config key**. Six
182
- simultaneous returns is six `../../_shared/return-validation.md` blocks in one
183
- orchestrator context, and this lane's orchestrator has a document to hold too.
184
- - Every return is validated per `../../_shared/return-validation.md`:
185
- `actual_model` and `actual_effort`, **quoted, never guessed**.
186
- - **A selected lens that did not run is NOT-RUN with a reason** — rule 6
187
- (`NOT-CHECKED` is never silent) extended to roles. The orchestrator writes
188
- `{ "lens": "contrarian", "ran": false, "reason": "…" }` into the verdict's
189
- `council[]`, and `record` accepts it. **Silence is rejected by name.**
190
-
191
- ### What each lens writes
192
-
193
- ```
194
- orc/orc-challenge/<slug>/iteration-NN/council/
195
- reader.md reader.json
196
- contrarian.md contrarian.json
197
- outsider.md outsider.json
198
- executor.md executor.json
199
- principles.md principles.json ← recorded by `note`, never by `record`
200
- expansionist.md expansionist.json ← recorded by `note`, never by `record`
201
- ```
202
-
203
- The `.md` is for the human and for the judge's slice. The `.json` is the machine
204
- half, and it is what makes the next section possible.
205
-
206
- ---
207
-
208
- ## Council conservation — the gate that makes this safe
209
-
210
- The obvious failure of adding five reviewers is that **the judge quietly ignores
211
- four of them** and the run looks identical while costing five times more.
212
-
213
- > **Every id the council raised must appear in the judge's return with exactly
214
- > ONE disposition and a reason. `council_coverage_pct` must be 100.**
215
-
216
- That is `conservation.md` applied to **input** instead of to carry-forward, and
217
- `orc challenge record` enforces it without reading a word of prose: **it reads
218
- `iteration-NN/council/*.json` ITSELF and derives the id set.** The judge cannot
219
- shrink it by omission, because the set was never the judge's to report.
220
-
221
- ### The disposition set — closed
222
-
223
- | Disposition | Meaning | Requires |
224
- |---|---|---|
225
- | `adopted` | the judge agrees; the finding enters `findings[]` under its own id | `severity`, `dimension`, `serves` |
226
- | `merged` | the same defect as another finding | `merged_into` (a resolvable id) |
227
- | `rejected` | the judge read the anchor and disagrees | `reason` |
228
- | `out-of-goal` | real, but traceable to no goal element | `reason` — and it is **reported**, never silently dropped |
229
-
230
- **`adopted` keeps the raiser's id.** `C-004` stays `C-004` in the verdict, in the
231
- report, in iteration 9. An id is permanent (`conservation.md`), and this is what
232
- lets the panel say *"the contrarian raised four of the six blockers this
233
- iteration"* — which is how a user finds out whether a lens is worth its money.
234
-
235
- ### Carrying forward across a changed roster
236
-
237
- Iteration 2 runs the contrarian, iteration 3 does not, and `C-004` is still open.
238
- Who resolves it?
239
-
240
- > **The judge resolves every carried finding, whatever prefix it carries.**
241
-
242
- Rule 11 already says a carried finding is re-judged **from the artifact on disk**,
243
- never from an account of what changed — so the judge never needed the original
244
- raiser. That makes the roster freely variable between iterations at zero cost to
245
- conservation, and it is why lenses may only *raise*.
246
-
247
- `record` therefore keeps its existing `coverage_pct` gate exactly as it was and
248
- adds `council_coverage_pct` beside it.
249
-
250
- ### The gates, each rejecting BY NAME (all exit 2)
251
-
252
- | Gate | Rejects |
253
- |---|---|
254
- | `council-unset` | the cycle's roster is `null` (a migrated v1 cycle) |
255
- | `unknown-lens` | a `lens` outside the catalogue |
256
- | `bad-prefix` | a finding whose id prefix disagrees with its lens |
257
- | `duplicate-id` | the same id from two lenses |
258
- | `lens-silent` | a roster lens with neither a report on disk nor `ran: false` + a reason |
259
- | `council-coverage` | any raised id missing a disposition — **the missing ids are named** |
260
- | `bad-disposition` | outside the set, `merged` without a resolvable `merged_into`, or `rejected`/`out-of-goal` with no reason |
261
- | `class-mismatch` | an opportunity or a premise inside `findings[]` |
262
- | `unknown-corroborator` | `corroborated_by` naming a lens that did not run this iteration |
263
-
264
- **PASS is computed exactly as before.** An adopted council finding is an ordinary
265
- finding from that moment on; `challengeBlocking()`, `challengeOpen()`,
266
- `challengeCounts()` and `challengeStateOf()` are untouched. **The pass gate
267
- learns nothing about the council**, which is what keeps rule 2 true.
268
-
269
- ---
270
-
271
- ## The frozen roster
272
-
273
- The roster is **not a config key.** A global default would silently answer the
274
- one question this whole design exists to ask. It is a per-cycle FROZEN decision
275
- in the ledger, changed only by a recorded `recouncil` event:
276
-
277
- ```bash
278
- orc challenge council <slug> --set contrarian,executor --reason "…"
279
- ```
280
-
281
- `council_version` increments exactly like `goals.version` and
282
- `template.version`, and the iteration rail draws a **third** version break for
283
- it — because comparing an iteration judged by three lenses to one judged by six
284
- is not a comparison.
285
-
286
- A cycle opened before v0.49.1 reads back with `council: null`, and `record`
287
- refuses the next iteration by name until the roster is answered. **A silent
288
- default would be ORC picking the council.**
289
-
290
- ---
291
-
292
- ## The trace
293
-
294
- `record` returns the line and the skill copies it **VERBATIM**:
295
-
296
- ```
297
- 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
298
- ```
299
-
300
- `council=4/5` is *lenses that ran / lenses on the roster*, so a NOT-RUN lens is
301
- visible in the trace, in `orc stats`, and to `/orc-retro` — not only in the
302
- panel.
303
-
304
- ---
305
-
306
- ## How the council fails — and what prevents each
307
-
308
- | Failure | Prevention |
309
- |---|---|
310
- | Five reviewers run and the judge ignores four | `council_coverage_pct`, computed from disk, never from the judge's account |
311
- | The expansionist's ideas get dropped for having no `serves` | the `opportunity` class — it never enters `findings[]` |
312
- | ORC decides which criticism the user is allowed to hear | rule 12, and `--council` has no default |
313
- | Six lenses, six wordings of one defect | `merged` + `corroborated_by`, and the per-lens raise counts make a useless lens visible within two iterations |
314
- | Reader and outsider collapse into one instrument | two different slices and two different return contracts — and when they agree, that is recorded as corroboration, not duplication |
315
- | A premise challenge destabilises every review | it never blocks, it resolves only by a human decision with a recorded reason, and a user who does not want their premise questioned simply does not select it |
1
+ # The council
2
+
3
+ > **A lens raises; only the judge resolves. ORC proposes the council; the user
4
+ > picks it.**
5
+
6
+ **a lane that picks its own council has broken this contract.**
7
+
8
+ That is the fourth member of a family, and the split is the same every time —
9
+ the facts are ORC's to look up, the decision is the user's to take:
10
+
11
+ | Lane | Broken by |
12
+ |---|---|
13
+ | `../../_shared/interview.md` | `a lane that answers its own interview question` |
14
+ | `/orc-brainstorm` | `a lane that picks its own favourite` |
15
+ | `/orc-challenge` | `a lane that fixes what it judged` |
16
+ | `/orc-doc` | `a lane that reads its own document` |
17
+ | **`/orc-challenge` council** | **`a lane that picks its own council`** |
18
+
19
+ A council chosen by ORC is ORC deciding **which kinds of criticism the user is
20
+ allowed to hear** — a bigger decision than any single finding in the run.
21
+
22
+ ---
23
+
24
+ ## The roster — seven lenses
25
+
26
+ One always runs. Six are selectable. **The user selects them.**
27
+
28
+ | Lens | Display | Agent | Effort | Class | Ids | Blocks? |
29
+ |---|---|---|---|---|---|---|
30
+ | `judge` | The Judge | `orc-challenge-judge-opus-5-high` | high | finding | `F-` | yes |
31
+ | `reader` | The Cold Reader | `orc-challenge-reader-opus-5-low` | low | finding | `R-` | yes |
32
+ | `contrarian` | The Contrarian | `orc-challenge-contrarian-opus-5-high` | high | finding | `C-` | yes |
33
+ | `outsider` | The Outsider | `orc-challenge-outsider-opus-5-low` | low | finding | `O-` | yes |
34
+ | `executor` | The Executor | `orc-challenge-executor-opus-5-med` | medium | finding | `E-` | yes |
35
+ | `principles` | The First Principles Thinker | `orc-challenge-principles-opus-5-high` | high | **premise** | `Q-` | **never** |
36
+ | `expansionist` | The Expansionist | `orc-challenge-expansionist-opus-5-med` | medium | **opportunity** | `X-` | **never** |
37
+
38
+ `orc-challenge-advisor-opus-5-med` is **not a lens.** It never inspects the
39
+ artifact for defects; it turns a FAIL into a fix strategy, and rule 5 still
40
+ holds: **no advisor on PASS.**
41
+
42
+ **Never hand-list these anywhere else.** `orc challenge roles --json` is the
43
+ catalogue; the P0 ask in `intake.md` renders it, and `orc ui` draws the roster
44
+ card from it. One list, three renderers — the Flow-stepper rule.
45
+
46
+ ### What each one is for, and how each one fails
47
+
48
+ | Role | It asks | It fails when |
49
+ |---|---|---|
50
+ | The Contrarian | "where is the fatal flaw?" | it assumes the artifact is fine and stops looking |
51
+ | The First Principles Thinker | "are we even solving the right problem?" | it accepts the framing it was handed |
52
+ | The Expansionist | "what is being undervalued here?" | it only counts what is wrong |
53
+ | The Outsider | "what does this assume I already know?" | it is an expert and cannot un-know things |
54
+ | The Executor | "what do you actually do on Monday morning?" | it grades the theory and never the first step |
55
+
56
+ ### Why each effort — and the rule that protects it
57
+
58
+ **Effort here is a measurement choice, not a cost choice.** The same sentence
59
+ governs the cold reader and the `/orc-doc` checker, and it now governs two more:
60
+
61
+ - **`outsider` is `low` for the same reason `reader` is.** A harder-thinking
62
+ outsider reasons its way *around* an unexplained acronym and reports that the
63
+ document is fine. The whole instrument is "do not reconstruct — report what is
64
+ actually on the page." **Nothing may ever upgrade it.**
65
+ - **`contrarian` is `high` because a shallow contrarian finds only the obvious.**
66
+ At low effort it returns the same three surface complaints the free lint
67
+ already caught.
68
+ - **`principles` is `high`** — rebuilding a problem statement from the ground up
69
+ is the deepest reasoning any role in this lane does.
70
+ - **`expansionist` and `executor` are `medium`** — pattern work against a
71
+ concrete artifact, the same class as the advisor.
72
+
73
+ All seven are `claude-opus-5-5`, so **`opus5_only` is a no-op for this lane: it is
74
+ unaffected, not exempt.** The agent count rises by exactly five, with no paired
75
+ variants (the v0.47.0 precedent).
76
+
77
+ ---
78
+
79
+ ## The reader / outsider seam — read this before touching either
80
+
81
+ These two are the closest pair in ORC, and the one place this design can produce
82
+ a duplicate instrument. The distinction is **structural, not stylistic**:
83
+
84
+ | | `reader` | `outsider` |
85
+ |---|---|---|
86
+ | Told the audience | **yes** | **no** |
87
+ | Told the goal / kind / template | no | no |
88
+ | What it generates | 8–15 questions **the artifact promised to answer**, from its own headings | nothing — it reacts to what is in front of it |
89
+ | What it returns | a **scored** questionnaire (`8/12`) + `R-###` | an **unscored** ranked list of assumed knowledge + `O-###` |
90
+ | The measurement | *can this be answered from the page?* | *what does this page assume you already know?* |
91
+ | Feeds | D4 | D5, and D4 where an assumption is load-bearing |
92
+
93
+ They are dispatched **with no knowledge of each other**, and their reports are
94
+ never merged before the judge reads them. **Where they agree, that is the
95
+ strongest comprehension evidence this lane can produce** — recorded as
96
+ `corroborated_by: [reader, outsider]`, and **never an automatic severity bump**
97
+ (the `/orc-aftermath` rule: churn is a signal, not a verdict).
98
+
99
+ ---
100
+
101
+ ## Three output classes — the honest split
102
+
103
+ ```
104
+ class: finding → judge, reader, contrarian, outsider, executor
105
+ class: opportunity → expansionist
106
+ class: premise → principles
107
+ ```
108
+
109
+ Two of the six cannot produce a finding **without lying**, and forcing them to
110
+ would be the single worst decision available here.
111
+
112
+ ### Why the expansionist cannot produce a finding
113
+
114
+ A finding must carry `serves` — the goal element it advances — and `record`
115
+ DROPS a finding without one (rule 0, structural). The expansionist's brief is
116
+ *"what upside is everyone missing?"*, which by construction is **not** in the
117
+ stated goal. Given a `serves` field it would either invent a goal element or be
118
+ silently dropped by the CLI.
119
+
120
+ ```yaml
121
+ opportunity:
122
+ id: X-002
123
+ what: "the retry table generalises to every idempotent write in the service"
124
+ upside: "…"
125
+ first_step: "…" # concrete; an upside with no first step is a daydream
126
+ anchor: "docs/tsd-payments.md:212"
127
+ confidence: medium
128
+ route: brainstorm # brainstorm | pact | grill | none
129
+ ```
130
+
131
+ **An opportunity never blocks, never has a severity, and never enters
132
+ `findings[]`.** It is conserved — `orc challenge opportunity <slug> <id>
133
+ --take|--drop --reason "…"`, both requiring a reason — and it is ROUTED: an
134
+ adopted one belongs in `/orc-brainstorm`, and one the user wants to commit to
135
+ belongs in `/orc-pact`. **This lane never builds it.**
136
+
137
+ ### Why the first-principles thinker cannot produce a finding
138
+
139
+ Its most valuable output is *"you are asking the wrong question entirely"* — and
140
+ in this lane the question is the **frozen goal**. A finding is measured against
141
+ the goal; a premise challenge disputes the **yardstick**. Those cannot be the
142
+ same object.
143
+
144
+ ```yaml
145
+ premise:
146
+ id: Q-001
147
+ disputes: goal # goal | audience | done_means | out_of_scope
148
+ quote: "<the exact line from goals.md it disputes>"
149
+ reframe: "…" # the problem restated from the ground up
150
+ what_changes: "…" # what this review would attack instead
151
+ cheapest_test: "…" # how to settle it without a rewrite
152
+ ```
153
+
154
+ **A premise challenge is resolved by a HUMAN and by nobody else.** Exactly two
155
+ resolutions exist:
156
+
157
+ 1. **Adopt** → `orc challenge goals <slug> --set <path> --reason "…"` — a
158
+ `regoal` event; `goals.version` increments, prior iterations keep their stamp,
159
+ and the iteration rail draws the version break. That mechanism has existed
160
+ since v0.47.0; the council is the first thing that can legitimately move it.
161
+ 2. **Dismiss** → `orc challenge premise <slug> <id> --dismiss --reason "…"`. The
162
+ reason is mandatory and stays visible in the report forever.
163
+
164
+ **The judge NEVER sees the premise report.** Handing a judge a document arguing
165
+ that the frozen goal is wrong biases every finding it produces afterwards.
166
+
167
+ > **The three finding lenses feed the judge. The two non-finding lenses feed the
168
+ > user.** That sentence is the whole architecture.
169
+
170
+ ---
171
+
172
+ ## C3 — dispatch discipline
173
+
174
+ The **judge slice is SEALED** as it always was — one row per FINDING lens, and
175
+ `principles.md` / `expansionist.md` are named as forbidden in `sealed-slice.md`.
176
+
177
+ - Every lens is dispatched **BY NAME**. An unnamed dispatch cannot enforce the
178
+ pin and is invisible to the trace hook (the v0.34.5 wiki-scanner lesson) — and
179
+ a by-name dispatch gets `SPAWN`/`RETURN` for free, which is how `/orc-retro`
180
+ can finally answer *"is the contrarian earning its dispatch?"*
181
+ - **Hard cap: 3 in flight**, announced when it bites, **no config key**. Six
182
+ simultaneous returns is six `../../_shared/return-validation.md` blocks in one
183
+ orchestrator context, and this lane's orchestrator has a document to hold too.
184
+ - Every return is validated per `../../_shared/return-validation.md`:
185
+ `actual_model` and `actual_effort`, **quoted, never guessed**.
186
+ - **A selected lens that did not run is NOT-RUN with a reason** — rule 6
187
+ (`NOT-CHECKED` is never silent) extended to roles. The orchestrator writes
188
+ `{ "lens": "contrarian", "ran": false, "reason": "…" }` into the verdict's
189
+ `council[]`, and `record` accepts it. **Silence is rejected by name.**
190
+
191
+ ### What each lens writes
192
+
193
+ ```
194
+ orc/orc-challenge/<slug>/iteration-NN/council/
195
+ reader.md reader.json
196
+ contrarian.md contrarian.json
197
+ outsider.md outsider.json
198
+ executor.md executor.json
199
+ principles.md principles.json ← recorded by `note`, never by `record`
200
+ expansionist.md expansionist.json ← recorded by `note`, never by `record`
201
+ ```
202
+
203
+ The `.md` is for the human and for the judge's slice. The `.json` is the machine
204
+ half, and it is what makes the next section possible.
205
+
206
+ ---
207
+
208
+ ## Council conservation — the gate that makes this safe
209
+
210
+ The obvious failure of adding five reviewers is that **the judge quietly ignores
211
+ four of them** and the run looks identical while costing five times more.
212
+
213
+ > **Every id the council raised must appear in the judge's return with exactly
214
+ > ONE disposition and a reason. `council_coverage_pct` must be 100.**
215
+
216
+ That is `conservation.md` applied to **input** instead of to carry-forward, and
217
+ `orc challenge record` enforces it without reading a word of prose: **it reads
218
+ `iteration-NN/council/*.json` ITSELF and derives the id set.** The judge cannot
219
+ shrink it by omission, because the set was never the judge's to report.
220
+
221
+ ### The disposition set — closed
222
+
223
+ | Disposition | Meaning | Requires |
224
+ |---|---|---|
225
+ | `adopted` | the judge agrees; the finding enters `findings[]` under its own id | `severity`, `dimension`, `serves` |
226
+ | `merged` | the same defect as another finding | `merged_into` (a resolvable id) |
227
+ | `rejected` | the judge read the anchor and disagrees | `reason` |
228
+ | `out-of-goal` | real, but traceable to no goal element | `reason` — and it is **reported**, never silently dropped |
229
+
230
+ **`adopted` keeps the raiser's id.** `C-004` stays `C-004` in the verdict, in the
231
+ report, in iteration 9. An id is permanent (`conservation.md`), and this is what
232
+ lets the panel say *"the contrarian raised four of the six blockers this
233
+ iteration"* — which is how a user finds out whether a lens is worth its money.
234
+
235
+ ### Carrying forward across a changed roster
236
+
237
+ Iteration 2 runs the contrarian, iteration 3 does not, and `C-004` is still open.
238
+ Who resolves it?
239
+
240
+ > **The judge resolves every carried finding, whatever prefix it carries.**
241
+
242
+ Rule 11 already says a carried finding is re-judged **from the artifact on disk**,
243
+ never from an account of what changed — so the judge never needed the original
244
+ raiser. That makes the roster freely variable between iterations at zero cost to
245
+ conservation, and it is why lenses may only *raise*.
246
+
247
+ `record` therefore keeps its existing `coverage_pct` gate exactly as it was and
248
+ adds `council_coverage_pct` beside it.
249
+
250
+ ### The gates, each rejecting BY NAME (all exit 2)
251
+
252
+ | Gate | Rejects |
253
+ |---|---|
254
+ | `council-unset` | the cycle's roster is `null` (a migrated v1 cycle) |
255
+ | `unknown-lens` | a `lens` outside the catalogue |
256
+ | `bad-prefix` | a finding whose id prefix disagrees with its lens |
257
+ | `duplicate-id` | the same id from two lenses |
258
+ | `lens-silent` | a roster lens with neither a report on disk nor `ran: false` + a reason |
259
+ | `council-coverage` | any raised id missing a disposition — **the missing ids are named** |
260
+ | `bad-disposition` | outside the set, `merged` without a resolvable `merged_into`, or `rejected`/`out-of-goal` with no reason |
261
+ | `class-mismatch` | an opportunity or a premise inside `findings[]` |
262
+ | `unknown-corroborator` | `corroborated_by` naming a lens that did not run this iteration |
263
+
264
+ **PASS is computed exactly as before.** An adopted council finding is an ordinary
265
+ finding from that moment on; `challengeBlocking()`, `challengeOpen()`,
266
+ `challengeCounts()` and `challengeStateOf()` are untouched. **The pass gate
267
+ learns nothing about the council**, which is what keeps rule 2 true.
268
+
269
+ ---
270
+
271
+ ## The frozen roster
272
+
273
+ The roster is **not a config key.** A global default would silently answer the
274
+ one question this whole design exists to ask. It is a per-cycle FROZEN decision
275
+ in the ledger, changed only by a recorded `recouncil` event:
276
+
277
+ ```bash
278
+ orc challenge council <slug> --set contrarian,executor --reason "…"
279
+ ```
280
+
281
+ `council_version` increments exactly like `goals.version` and
282
+ `template.version`, and the iteration rail draws a **third** version break for
283
+ it — because comparing an iteration judged by three lenses to one judged by six
284
+ is not a comparison.
285
+
286
+ A cycle opened before v0.49.1 reads back with `council: null`, and `record`
287
+ refuses the next iteration by name until the roster is answered. **A silent
288
+ default would be ORC picking the council.**
289
+
290
+ ---
291
+
292
+ ## The trace
293
+
294
+ `record` returns the line and the skill copies it **VERBATIM**:
295
+
296
+ ```
297
+ 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
298
+ ```
299
+
300
+ `council=4/5` is *lenses that ran / lenses on the roster*, so a NOT-RUN lens is
301
+ visible in the trace, in `orc stats`, and to `/orc-retro` — not only in the
302
+ panel.
303
+
304
+ ---
305
+
306
+ ## How the council fails — and what prevents each
307
+
308
+ | Failure | Prevention |
309
+ |---|---|
310
+ | Five reviewers run and the judge ignores four | `council_coverage_pct`, computed from disk, never from the judge's account |
311
+ | The expansionist's ideas get dropped for having no `serves` | the `opportunity` class — it never enters `findings[]` |
312
+ | ORC decides which criticism the user is allowed to hear | rule 12, and `--council` has no default |
313
+ | Six lenses, six wordings of one defect | `merged` + `corroborated_by`, and the per-lens raise counts make a useless lens visible within two iterations |
314
+ | Reader and outsider collapse into one instrument | two different slices and two different return contracts — and when they agree, that is recorded as corroboration, not duplication |
315
+ | A premise challenge destabilises every review | it never blocks, it resolves only by a human decision with a recorded reason, and a user who does not want their premise questioned simply does not select it |