the-high-council 0.7.8 → 0.8.0
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/README.md +39 -16
- package/chains/cheap-7-v2.json +1 -0
- package/chains/local-ollama.json +1 -0
- package/chains/plan-daily-7.json +44 -0
- package/chains/plan-highest-7.json +4 -3
- package/chains/plan-premium-7.json +1 -0
- package/chains/security-review-only.json +29 -0
- package/package.json +1 -1
- package/schemas/report-v1.json +142 -5
- package/src/api.js +21 -9
- package/src/cache-integrity.js +5 -1
- package/src/chain-lint.js +34 -1
- package/src/chain.js +287 -43
- package/src/cli.js +441 -38
- package/src/criteria-kinds.js +7 -1
- package/src/criteria-ledger.js +38 -0
- package/src/criteria-lints.js +51 -0
- package/src/criteria-lock.js +80 -0
- package/src/decision-records.js +54 -0
- package/src/denied-models.js +19 -2
- package/src/dissent-digest.js +4 -0
- package/src/dry-run.js +86 -0
- package/src/handoff-from-run.js +80 -0
- package/src/mcp/server.js +50 -17
- package/src/outbound-scan.js +59 -0
- package/src/partial-deliverable.js +5 -0
- package/src/pricing.json +33 -3
- package/src/providers.js +55 -0
- package/src/report-shape.js +33 -4
- package/src/run-status.js +38 -2
- package/src/scope-freeze.js +46 -3
- package/src/secret-patterns.js +11 -6
- package/src/security-review.js +1 -1
- package/src/spans.js +25 -5
- package/src/spend.js +11 -2
- package/src/ui/app.js +12 -3
- package/src/ui/guard.js +94 -0
- package/src/ui/server.js +22 -11
- package/src/ui/style.css +2 -0
- package/src/verdict-diff.js +6 -1
- package/src/withdrawal-ledger.js +9 -4
- package/types/index.d.ts +6 -1
package/README.md
CHANGED
|
@@ -7,7 +7,8 @@ You choose the number of debate rounds, the seats and labs (any lab except xAI),
|
|
|
7
7
|
limit for each model's replies.
|
|
8
8
|
|
|
9
9
|
We recommend our own chains: `cheap-7-v2`, `plan-premium-7` and `plan-highest-7` (the top
|
|
10
|
-
models, GPT-6 Astra, Claude
|
|
10
|
+
models, GPT-6 Astra, Claude Opus 5.5, DeepSeek V4 Pro
|
|
11
|
+
and GLM-5.3, write the alternative
|
|
11
12
|
architectures and are the only seats that vote; cheaper seats write the proposals and the debate). You can also edit a chain to suit yourself, or run every seat on
|
|
12
13
|
your own machine with `local-ollama`.
|
|
13
14
|
|
|
@@ -40,8 +41,8 @@ Three commands from nothing to a priced run of your own idea (no key needed unti
|
|
|
40
41
|
| Chain | Who does what | Needs | Worst case |
|
|
41
42
|
|---|---|---|---|
|
|
42
43
|
| `cheap-7-v2` | Claude Sonnet 5 writes the plan; low-cost models from seven other labs review it, and all seven must sign off. Up to 7 rounds. | one OpenRouter key | $5.38 |
|
|
43
|
-
| `plan-premium-7` | A Claude Code session writes the plan; a seven-lab panel of larger models (GPT-6 Astra, Claude Fable 5.1, Gemini 3.8 Flash, Muse Spark 1.2, Qwen 3.8 Max, DeepSeek V4 Pro, GLM-5.3) proposes, debates and reviews. | OpenRouter key + a Claude Code session | $
|
|
44
|
-
| `plan-highest-7` | Seven low-cost models propose and debate; four top models write whole architectures and are the only reviewers; one deep-dive seat checks the first draft against the task. **Untested with real models.** | OpenRouter key + a Claude Code session | $
|
|
44
|
+
| `plan-premium-7` | A Claude Code session writes the plan; a seven-lab panel of larger models (GPT-6 Astra, Claude Fable 5.1, Gemini 3.8 Flash, Muse Spark 1.2, Qwen 3.8 Max, DeepSeek V4 Pro, GLM-5.3) proposes, debates and reviews. | OpenRouter key + a Claude Code session | $22.30 |
|
|
45
|
+
| `plan-highest-7` | Seven low-cost models propose and debate; four top models write whole architectures and are the only reviewers; one deep-dive seat checks the first draft against the task. **Untested with real models.** | OpenRouter key + a Claude Code session | $11.21 |
|
|
45
46
|
| `local-ollama` | Every seat on your own machine, through Ollama. | Ollama and the models pulled | $0 |
|
|
46
47
|
|
|
47
48
|
`plan-premium-7` and `plan-highest-7` cost more than the default cap, so give them a `--max-usd` at
|
|
@@ -147,7 +148,10 @@ A run moves through fixed stages. Which stages fire depends on the chain you pic
|
|
|
147
148
|
7. **Panel review** - every critic independently grades the draft against the acceptance criteria,
|
|
148
149
|
blind. Not unanimous? It revises against the union of every objection and the panel reviews
|
|
149
150
|
again, up to the chain's round cap.
|
|
150
|
-
8. **Handoff** - a `HANDOFF.md` written for whoever executes the result.
|
|
151
|
+
8. **Handoff** - a `HANDOFF.md` written for whoever executes the result. It ends with a block the
|
|
152
|
+
harness writes, not a model: the acceptance criteria the run settled, with a fingerprint.
|
|
153
|
+
`council check-lock HANDOFF.md` ($0) says whether a copy still carries them; it catches an edit or
|
|
154
|
+
a slip, and is not a signature.
|
|
151
155
|
|
|
152
156
|
Some chains add optional stages to this: whole alternative architectures written blind before
|
|
153
157
|
the skeleton, a deep-dive check of the first draft, a dispute stage that records unresolved
|
|
@@ -156,6 +160,12 @@ objections at the top of the plan, and a final security review.
|
|
|
156
160
|
Every run writes a folder: the deliverable, `BOARD.md` (the full debate - every post, every
|
|
157
161
|
withdrawal), `HANDOFF.md`, a per-lab scoreboard, and the real token/cost accounting.
|
|
158
162
|
|
|
163
|
+
A run that stopped before it wrote its handoff (the spend cap, an abandoned pause, a crash) can get one from
|
|
164
|
+
its latest draft: `council handoff --from-run runs/<id>`. It is one call on the chain's handoff seat, under the
|
|
165
|
+
run's own spend cap (what the folder already cost counts toward it; `--max-usd N` is a total, as on `--resume`),
|
|
166
|
+
the same policy check and key scan as a run, and a run no panel signed off gets a note at the top, written by
|
|
167
|
+
the harness, saying so. It never overwrites an existing `HANDOFF.md`.
|
|
168
|
+
|
|
159
169
|
### Reading a run with a program
|
|
160
170
|
|
|
161
171
|
`BOARD.md` is for people. **`report.json` is the same board, structured** - if you are building
|
|
@@ -275,8 +285,8 @@ ones. Put only the keys your chosen chain needs in that `.env`, one `NAME=value`
|
|
|
275
285
|
`DEEPSEEK_API_KEY` · `GROQ_API_KEY` · `TOGETHER_API_KEY` · `COHERE_API_KEY` ·
|
|
276
286
|
`OPENROUTER_API_KEY` · `ZAI_API_KEY`
|
|
277
287
|
|
|
278
|
-
xAI/Grok is never seated, and neither is a router id (`openrouter/auto`, the Pareto Code router
|
|
279
|
-
that could route to it: chain-lint refuses such a chain and the run itself refuses such a seat,
|
|
288
|
+
xAI/Grok is never seated, and neither is a router id (`openrouter/auto`, the Pareto Code router,
|
|
289
|
+
any other `openrouter/<name>` id) that could route to it: chain-lint refuses such a chain and the run itself refuses such a seat,
|
|
280
290
|
with no override. There is no `xai` provider. Kimi/Moonshot models are not in any chain this
|
|
281
291
|
package ships, but you may seat one in a chain of your own.
|
|
282
292
|
|
|
@@ -419,10 +429,10 @@ Each outcome has its own code, so a script or CI job can branch on it:
|
|
|
419
429
|
| 8 | Finished, but the final security review could not judge it (never a pass). |
|
|
420
430
|
| 9 | Artifact gate: the task names files whose content it never includes (`BLOCKED-ARTIFACTS.md`). |
|
|
421
431
|
| 10 | Preflight: a seat objected to the task description itself (`STOPPED-preflight.md`). |
|
|
422
|
-
| 11 |
|
|
432
|
+
| 11 | Something in the input must not be sent: a prompt matches one of the key formats listed in `src/secret-patterns.js` (checked by default; `--allow-secret-shaped` overrides), or, under `--pii-gate hard-stop`, a PII shape. |
|
|
423
433
|
| 12 | `policy.json` refused the chain. |
|
|
424
434
|
| 13 | Another process is already running this run folder. |
|
|
425
|
-
| 14 | The task file changed since the run started and `AMENDMENTS.md` does not cover it. |
|
|
435
|
+
| 14 | The task file, or (since 0.8.0) a `--context` document, changed since the run started and `AMENDMENTS.md` does not cover it. The message prints the hashes to write; a context hash is written `ctx-<hash>`. |
|
|
426
436
|
| 15 | `--resume` of a run that already finished (it has a `report.json`); nothing is run or spent. |
|
|
427
437
|
| 16 | The run stopped at an unexpected error (a seat that could not be reached, a crash); `STOPPED-error.md` says what, and `--resume` continues from the completed stages. |
|
|
428
438
|
| 17 | A draft (build, revise, dispute, final edit or handoff) was cut off at its token cap, and its one larger-cap retry was cut off too; the fragment is never graded or shipped (`STOPPED-truncated.md`). |
|
|
@@ -460,7 +470,7 @@ than reporting the overspend afterwards.
|
|
|
460
470
|
|
|
461
471
|
```bash
|
|
462
472
|
council --task tasks/x.md --max-usd 2 # this run stops at $2
|
|
463
|
-
council --task tasks/x.md --max-usd none # no ceiling
|
|
473
|
+
council --task tasks/x.md --max-usd none # no ceiling (0 is refused: it used to mean this)
|
|
464
474
|
export MAX_USD_PER_RUN=20 # change the default
|
|
465
475
|
```
|
|
466
476
|
|
|
@@ -612,7 +622,7 @@ for anyone with a subscription, since the project's cost story depends on it.
|
|
|
612
622
|
|
|
613
623
|
## Chains
|
|
614
624
|
|
|
615
|
-
|
|
625
|
+
52 chain configs live in `chains/`. Each one is plain JSON - the seat roster, which models fill
|
|
616
626
|
which seat, the round cap, and whether proposals/debate/handoff stages run. They are meant to be
|
|
617
627
|
copied and edited.
|
|
618
628
|
|
|
@@ -623,6 +633,12 @@ in the table at the top. A few more worth knowing:
|
|
|
623
633
|
and Google keys.
|
|
624
634
|
- **`plan-open-7`** - the `cheap-7-v2` panel, with a Claude Code session writing the plan instead
|
|
625
635
|
of a paid seat.
|
|
636
|
+
- **`plan-daily-7`** - `plan-highest-7`'s stages at a lower price, for planning one feature:
|
|
637
|
+
Claude Opus 5.5 on your Claude subscription (an external seat), GPT-6 Luna and DeepSeek V4 Pro
|
|
638
|
+
write the architectures and alone vote; seven low-cost labs propose and debate. Two Claude Code
|
|
639
|
+
sessions answer its external seats: Opus 5.5 every stage whose label contains `opus5.5-sub`
|
|
640
|
+
(including `-retry` and `-reask1`/`-reask2` forms), Sonnet 5 the writer stages. $1.90 worst case.
|
|
641
|
+
**Run once with real models (2026-09-28); nothing about it has been measured.**
|
|
626
642
|
- **`cheap`** - small models throughout. For testing the harness itself, not for real work.
|
|
627
643
|
- **`plan-debate`** - five labs propose blind, debate each other's proposals anonymised, then a
|
|
628
644
|
blind panel grades the integrated draft.
|
|
@@ -654,7 +670,7 @@ Read a chain's `description` field before running it; they say what they cost yo
|
|
|
654
670
|
- **`quorum: { "minHeard": N }`** - opt-in, unanimous chains only, set in no shipped chain. A
|
|
655
671
|
round's sign-off counts only when at least N reviewers gave a verdict (signed off or objected);
|
|
656
672
|
a round short of it is recorded as `notQuorate`, the run does not pass, and the loop stops.
|
|
657
|
-
- **Tiered councils (experimental, used by `plan-highest-7` and `mock-tiered`).**
|
|
673
|
+
- **Tiered councils (experimental, used by `plan-highest-7`, `plan-daily-7` and `mock-tiered`).**
|
|
658
674
|
`seats.alternatives` names who writes the whole alternative architectures, separately from the
|
|
659
675
|
proposers. `deep_dive` + `seats.deep_dive` add one non-voting seat with its own dollar cap
|
|
660
676
|
(`usd`, required) inside the run's cap. `majority_guard.enabled` shows each author every
|
|
@@ -720,6 +736,9 @@ what each rule guards against and why. Copy the folders you want into your proje
|
|
|
720
736
|
input plus the seat's entire `maxTokens` budget billed as output (doubled for Anthropic seats,
|
|
721
737
|
which may retry once). Real stages almost never cost that much, so a run can stop with headroom
|
|
722
738
|
left. That is the intended trade - resume it with a higher ceiling.
|
|
739
|
+
- The dry run (`--dry-run`, MCP `dry_run`) prices the task alone and does not read `--context`
|
|
740
|
+
documents, so for a run with context its estimate is too low. The spend cap is not affected: it
|
|
741
|
+
checks every real prompt, context included, before each call.
|
|
723
742
|
- A seat whose model has no entry in `src/pricing.json` is **unpriced, and therefore uncapped**.
|
|
724
743
|
It contributes $0 to the running total no matter what it really costs. Check `dry_run` output
|
|
725
744
|
for `unpriced` before trusting a ceiling. `ollama` seats are the one deliberate exception: they
|
|
@@ -740,11 +759,11 @@ what each rule guards against and why. Copy the folders you want into your proje
|
|
|
740
759
|
oldest date every entry was last checked) is printed by `council doctor` and `--dry-run`, with a
|
|
741
760
|
warning once it is more than 60 days old. The spend cap and every estimate use these static
|
|
742
761
|
prices. They are estimates, not invoices. Your provider's bill is the real number.
|
|
743
|
-
- `plan-highest-7
|
|
744
|
-
mechanisms (tiers, the deep-dive seat, the majority
|
|
745
|
-
|
|
746
|
-
- Seats marked `external` (the writer seats in `plan-premium-7`, `plan-highest-7
|
|
747
|
-
`plan-open-7`) pause the run until someone answers them, and are $0 only because a Claude Code
|
|
762
|
+
- `plan-highest-7` has not been run with real models, and `plan-daily-7` has run once
|
|
763
|
+
(2026-09-28). None of the tiered councils' mechanisms (tiers, the deep-dive seat, the majority
|
|
764
|
+
guard) has been measured. Their dry-run prices are projections.
|
|
765
|
+
- Seats marked `external` (the writer seats in `plan-premium-7`, `plan-highest-7`,
|
|
766
|
+
`plan-daily-7` and `plan-open-7`, and the Opus 5.5 anchor seat in `plan-daily-7`) pause the run until someone answers them, and are $0 only because a Claude Code
|
|
748
767
|
session on a subscription writes them. Nothing checks who wrote the answer.
|
|
749
768
|
- Chains with many labs and high round caps get expensive quickly. `plan-unanimous` at three rounds
|
|
750
769
|
is fifteen critic calls; `plan-auto` runs several frontier models over multiple rounds. Price
|
|
@@ -758,6 +777,10 @@ what each rule guards against and why. Copy the folders you want into your proje
|
|
|
758
777
|
which is the default, it does not detect a full rewrite**: anyone who can edit the file can
|
|
759
778
|
recompute every hash. Set `AUDIT_HMAC_KEY_FILE` to a key kept outside the run folder if the log
|
|
760
779
|
has to stand up to that.
|
|
780
|
+
- The outbound key scan matches **key shapes only**, the formats in `src/secret-patterns.js`; a
|
|
781
|
+
password written in prose is not detectable. Generic shapes (a password inside a URL or an
|
|
782
|
+
assignment) are checked in your inputs before the run; text the models write is checked only for
|
|
783
|
+
distinctive key formats.
|
|
761
784
|
|
|
762
785
|
## Privacy
|
|
763
786
|
|
package/chains/cheap-7-v2.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cheap-7-v2",
|
|
3
3
|
"description": "Seven independent labs vote, none of them the author's, all on current-generation models through one OpenRouter key: OpenAI GPT-5.6 Luna, Google Gemini 3.8 Flash, DeepSeek v4.1 Flash, Z.ai GLM 5.3 Flash, Qwen 3.7 Plus, MiniMax M3, Mistral Medium 3.5. Blind proposals, debate, unanimous signoff, with a round cap of 7 and a stall rule: if the same objections from the same labs survive two rounds running, the revise loop stops rather than buying more rounds of the same argument, and the unresolved dissent is recorded at the top of the deliverable. A run that ends that way reports no consensus - the dispute stage records disagreement, it never resolves it. Anthropic Sonnet 5 writes the skeleton, the draft, every revision and the handoff and holds NO panel seat; Meta Llama 4 Maverick writes the criteria and also holds no panel seat, so neither the lab that drafts nor the lab that sets the bar votes on whether the bar was cleared. This is the revision of cheap-7 after its first real run, where one lab held the criteria, skeleton, builder, reviser and handoff seats AND a critic seat, voted on its own draft, and a claim it wrote survived to the deliverable. Anthropic is deliberately absent from the panel: plans from this chain are read by a Claude session before anything is built, so that review happens downstream rather than inside the vote. Kimi K3 is deliberately absent too - a seat that may route through another lab is not an independent seat. Every seat gets a 36000-token ceiling and reasoning is left on: a debate is not squeezed to a short answer, and a reply cut off at the ceiling is retried once, then the seat is re-asked alone - it is never counted as agreement. The cap is a ceiling, not a price; only generated tokens are billed. Prices are from src/pricing.json, refreshed against OpenRouter's live model list on 2026-09-20 - price a real task with `npm run dry` before running.",
|
|
4
|
+
"summary": "Seven labs on one OpenRouter key: blind proposals, debate, unanimous sign-off.",
|
|
4
5
|
"maxRounds": 7,
|
|
5
6
|
"signoff": "unanimous",
|
|
6
7
|
"dispute": {
|
package/chains/local-ollama.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-ollama",
|
|
3
3
|
"description": "BYO-hardware: every seat runs on a local Ollama instance. No API key, no spend - `dry_run` prices this chain at $0. Swap the model names for whatever you've pulled (`ollama pull <model>`); swap `baseUrl` if Ollama (or an LM Studio / other OpenAI-compatible local runner) listens somewhere other than the default `http://localhost:11434/v1`.",
|
|
4
|
+
"summary": "Every seat on a local Ollama model: no API key and no spend.",
|
|
4
5
|
"maxRounds": 2,
|
|
5
6
|
"stopOnPass": true,
|
|
6
7
|
"estimate": {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "plan-daily-7",
|
|
3
|
+
"description": "daily7 (the owner's name, 2026-09-27: cheap API seats, and the expensive Opus 5.5 seat runs on a local Claude Code session). Tiered council for planning ONE feature cheaply (Muad, 2026-09-27: \"Opus 5.5 on a local sub that does the important tasks from the highest7 setup ... all together ~1$ per council run\"). Same stages and flags as plan-highest-7 (alternatives, debate, decision records, deep dive, majority guard ON, canary, dispute, handoff); only the seats and the deep-dive cap differ. ANCHOR SEATS write the whole alternative architectures (seats.alternatives), answer the posts on them, and are the only panel that votes, unanimously (seats.critics): Claude Opus 5.5 on the owner's Claude subscription (provider external, model subscription:opus-5.5, lab opus5.5-sub: $0 API, a separate Opus 5.5 Claude Code session answers its paused stages), GPT-6 Luna and DeepSeek V4 Pro through OpenRouter. MASS SEATS (seats.proposers, seven labs from the strong and low-cost part of arena.ai's agent leaderboard, fetched 2026-09-27): Tencent Hy4 preview, Gemini 3.8 Flash, DeepSeek V4.1 Flash, GLM 5.2, Muse Spark 1.3, Qwen 3.8 Max, Mistral Medium 3.5 (kept on the owner's word) write the blind proposals and every debate post and reply, and post on the anchors' architectures (alternatives.debaters \"all\"); they argue, they never vote. DEEP-DIVE SEAT: DeepSeek V4.1 Flash, a mass-tier model (a different model from the voting V4 Pro, so chain-lint deep-dive-votes passes), under its own $0.50 cap: a feature-sized task is one 40,000-character call, and a $4 sub-cap would be larger than this chain's whole worst case. Criteria: Llama 4 Maverick, which holds no other seat. WRITER SEATS (skeleton, build, deep-dive-revise, revise-N, dispute, handoff) are a Claude Code session running Sonnet 5, which builds and holds no panel seat. The Opus 5.5 panel seat is a DIFFERENT Anthropic model in a separate session: the owner's plan-highest-7 exception (an Anthropic model reviews a draft another Claude writes), not selfReview - no model writes and votes. ROUTING, because a NEEDS file names only its label: every label containing opus5.5-sub goes to the Opus 5.5 session (alternative-, alt-debate-, alt-reply-, panel-N-, including the suffixed forms panel-N-opus5.5-sub-retry, -reask1, -reask2 and alternative-opus5.5-sub-retry); skeleton, build, deep-dive-revise, revise-N, dispute and handoff go to the Sonnet 5 session. Nothing checks who wrote an answer. Dry run on a one-page feature task (2026-09-27, GPT-6 Luna in place of GPT-6 Sol on the owner's word: \"GPT 6 Sol is too expensive, take GPT 6 luna\"): $1.90 worst case at 7 rounds; under the default $7 cap. No Kimi, no xAI. Run once with real models (2026-09-28); none of its mechanisms has been measured. Price your task with `npm run dry` and get an explicit go before any paid run.",
|
|
4
|
+
"summary": "One feature: three anchors write architectures and vote, seven low-cost labs debate; Opus 5.5 via your Claude plan.",
|
|
5
|
+
"maxRounds": 7,
|
|
6
|
+
"signoff": "unanimous",
|
|
7
|
+
"dispute": { "enabled": true, "stall_rounds": 2 },
|
|
8
|
+
"proposals": { "parts": 3, "maxTokens": 4000 },
|
|
9
|
+
"debate": true,
|
|
10
|
+
"decisions": { "enabled": true },
|
|
11
|
+
"alternatives": { "enabled": true, "debaters": "all" },
|
|
12
|
+
"deep_dive": { "enabled": true, "job": "sources", "usd": 0.5, "maxCalls": 24, "chunkChars": 40000 },
|
|
13
|
+
"majority_guard": { "enabled": true },
|
|
14
|
+
"canary": { "enabled": true, "sampleRate": 0.1 },
|
|
15
|
+
"handoff": true,
|
|
16
|
+
"estimate": { "promptTokens": 10000, "draftTokens": 10000, "critiqueTokens": 5000 },
|
|
17
|
+
"seats": {
|
|
18
|
+
"criteria": { "provider": "openrouter", "model": "meta-llama/llama-4-maverick", "maxTokens": 36000, "lab": "llama4-maverick" },
|
|
19
|
+
"skeleton": { "provider": "external", "model": "claude-code-session" },
|
|
20
|
+
"builder": { "provider": "external", "model": "claude-code-session" },
|
|
21
|
+
"reviser": { "provider": "external", "model": "claude-code-session" },
|
|
22
|
+
"handoff": { "provider": "external", "model": "claude-code-session" },
|
|
23
|
+
"proposers": [
|
|
24
|
+
{ "provider": "openrouter", "model": "tencent/hy4-preview", "maxTokens": 36000, "lab": "hy4-preview" },
|
|
25
|
+
{ "provider": "openrouter", "model": "google/gemini-3.8-flash", "maxTokens": 36000, "lab": "gemini3.8-flash" },
|
|
26
|
+
{ "provider": "openrouter", "model": "deepseek/deepseek-v4.1-flash", "maxTokens": 36000, "lab": "deepseek-v4.1-flash" },
|
|
27
|
+
{ "provider": "openrouter", "model": "z-ai/glm-5.2", "maxTokens": 36000, "lab": "glm5.2" },
|
|
28
|
+
{ "provider": "openrouter", "model": "meta/muse-spark-1.3", "maxTokens": 36000, "lab": "muse-spark1.3" },
|
|
29
|
+
{ "provider": "openrouter", "model": "qwen/qwen3.8-max-0902", "maxTokens": 36000, "lab": "qwen3.8-max" },
|
|
30
|
+
{ "provider": "openrouter", "model": "mistralai/mistral-medium-3-5", "maxTokens": 36000, "lab": "mistral-medium3.5" }
|
|
31
|
+
],
|
|
32
|
+
"alternatives": [
|
|
33
|
+
{ "provider": "external", "model": "subscription:opus-5.5", "lab": "opus5.5-sub" },
|
|
34
|
+
{ "provider": "openrouter", "model": "openai/gpt-6-luna", "maxTokens": 36000, "lab": "gpt6-luna" },
|
|
35
|
+
{ "provider": "openrouter", "model": "deepseek/deepseek-v4-pro", "maxTokens": 64000, "lab": "deepseek-v4-pro" }
|
|
36
|
+
],
|
|
37
|
+
"critics": [
|
|
38
|
+
{ "provider": "external", "model": "subscription:opus-5.5", "lab": "opus5.5-sub" },
|
|
39
|
+
{ "provider": "openrouter", "model": "openai/gpt-6-luna", "maxTokens": 36000, "lab": "gpt6-luna" },
|
|
40
|
+
{ "provider": "openrouter", "model": "deepseek/deepseek-v4-pro", "maxTokens": 64000, "lab": "deepseek-v4-pro" }
|
|
41
|
+
],
|
|
42
|
+
"deep_dive": { "provider": "openrouter", "model": "deepseek/deepseek-v4.1-flash", "maxTokens": 36000, "lab": "deepseek-v4.1-flash" }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plan-highest-7",
|
|
3
|
-
"description": "Tiered council, Muad's design (2026-09-26): the highest models for the highest tasks, the cheapest models for the mass work. MASS SEATS (seats.proposers, the cheap-7-v2 roster: GPT-5.6 Luna, Gemini 3.8 Flash, DeepSeek V4.1 Flash, GLM 5.3 Flash, Qwen 3.7 Plus, MiniMax M3, Mistral Medium 3.5) write the blind proposals and all the proposal debate posts and replies, and post on the anchors' architectures (alternatives.debaters \"all\"). ANCHOR SEATS: GPT-6 Astra and Claude Fable 5.1
|
|
3
|
+
"description": "Tiered council, Muad's design (2026-09-26): the highest models for the highest tasks, the cheapest models for the mass work. MASS SEATS (seats.proposers, the cheap-7-v2 roster: GPT-5.6 Luna, Gemini 3.8 Flash, DeepSeek V4.1 Flash, GLM 5.3 Flash, Qwen 3.7 Plus, MiniMax M3, Mistral Medium 3.5) write the blind proposals and all the proposal debate posts and replies, and post on the anchors' architectures (alternatives.debaters \"all\"). ANCHOR SEATS: GPT-6 Astra and Claude Opus 5.5 (Muad's pick 2026-09-26, in place of Fable 5.1; still his deliberate exception: an Anthropic model reviews a draft a Claude Code session writes), DeepSeek V4 Pro and GLM-5.3 write the whole alternative architectures (seats.alternatives), answer the posts on them, and form the review panel that must sign off unanimously (seats.critics). The mass seats argue; only the anchors vote, so a cheap majority can never out-vote them. DEEP-DIVE SEAT (seats.deep_dive, DeepSeek V4.1 Flash, a mass-tier model: it must not share a lab with a voting anchor, chain-lint deep-dive-votes): one job, checking the first draft against every part of the task, 40,000 characters per call at a 36k output cap, up to 24 calls under its OWN $4 cap inside the run's; it does not vote, and the reviser answers its findings before the anchors' first review. The MAJORITY GUARD is ON (majority_guard, Muad's go 2026-09-26; off in every other shipped chain but mock-tiered): authors see each argument once with no lab letter or count, the reply prompts carry an evidence bar, and a withdrawal that does not quote the argument it concedes to is kept for the builder. Criteria move to Llama 4 Maverick, which holds no other seat. Same Claude Code writer seats and stages as plan-premium-7, including decision records and the dispute stage. No Kimi, no xAI. Untested with real models: price it with `npm run dry` and get an explicit go before any paid run.",
|
|
4
|
+
"summary": "Four anchor labs write architectures and vote; seven low-cost labs write proposals and debate.",
|
|
4
5
|
"maxRounds": 7,
|
|
5
6
|
"signoff": "unanimous",
|
|
6
7
|
"dispute": { "enabled": true, "stall_rounds": 2 },
|
|
@@ -30,13 +31,13 @@
|
|
|
30
31
|
],
|
|
31
32
|
"alternatives": [
|
|
32
33
|
{ "provider": "openrouter", "model": "openai/gpt-6-astra", "maxTokens": 36000, "lab": "gpt6-astra" },
|
|
33
|
-
{ "provider": "openrouter", "model": "anthropic/claude-
|
|
34
|
+
{ "provider": "openrouter", "model": "anthropic/claude-opus-5.5", "maxTokens": 36000, "lab": "opus5.5", "estimate": { "critiqueTokens": 10000 } },
|
|
34
35
|
{ "provider": "openrouter", "model": "deepseek/deepseek-v4-pro", "maxTokens": 64000, "lab": "deepseek-v4-pro" },
|
|
35
36
|
{ "provider": "openrouter", "model": "z-ai/glm-5.3", "maxTokens": 64000, "lab": "glm5.3" }
|
|
36
37
|
],
|
|
37
38
|
"critics": [
|
|
38
39
|
{ "provider": "openrouter", "model": "openai/gpt-6-astra", "maxTokens": 36000, "lab": "gpt6-astra" },
|
|
39
|
-
{ "provider": "openrouter", "model": "anthropic/claude-
|
|
40
|
+
{ "provider": "openrouter", "model": "anthropic/claude-opus-5.5", "maxTokens": 36000, "lab": "opus5.5", "estimate": { "critiqueTokens": 10000 } },
|
|
40
41
|
{ "provider": "openrouter", "model": "deepseek/deepseek-v4-pro", "maxTokens": 64000, "lab": "deepseek-v4-pro" },
|
|
41
42
|
{ "provider": "openrouter", "model": "z-ai/glm-5.3", "maxTokens": 64000, "lab": "glm5.3" }
|
|
42
43
|
],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plan-premium-7",
|
|
3
3
|
"description": "Premium panel, Muad's roster (2026-09-22): OpenAI GPT-6 Astra, Anthropic Claude Fable 5.1, Google Gemini 3.8 Flash, Meta Muse Spark 1.2, Qwen 3.8 Max, DeepSeek V4 Pro, Z.ai GLM-5.3 - seven labs, same stages and external Claude-role seats as plan-open-7. DELIBERATE EXCEPTION, Muad's call: an Anthropic model (Fable 5.1) sits on the panel although the draft is written by a Claude Code session, so this panel is not fully independent of the drafting lab - read its sign-off with that in mind. Criteria move to Mistral Medium 3.5, which holds no panel seat, because Meta now votes. No Kimi K3, no xAI. Each seat carries a persona (debate stage only; see PERSONAS.md): the five defaults plus Hypatia and Avicenna via COUNCIL_PERSONAS_FILE. Several times the cost of plan-open-7: price with `npm run dry` and get an explicit go first. Decision records and whole alternative architectures on (2026-09-23): each lab blind-proposes one whole architecture before the skeleton, the labs debate them, and the plan's Decisions section records why the losers lost.",
|
|
4
|
+
"summary": "Seven premium-tier labs argue whole architectures first; a Claude Code session writes the drafts.",
|
|
4
5
|
"maxRounds": 7,
|
|
5
6
|
"signoff": "unanimous",
|
|
6
7
|
"dispute": {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "security-review-only",
|
|
3
|
+
"description": "A tiny chain whose only real content is a human-supplied artifact and the final security-review gate (515439a, docs/security-review-gate.md). The builder seat is external: the CLI pauses, an operator (a person or an orchestrator like Sophi-A) pastes the artifact under review as the paused stage's own <label>.md, and resumes. No criteria call (criteria is hardcoded so that stage never runs) and one always-passing mock critic round, present only because chain-lint requires at least one seats.critics entry - this chain's real gate is security_review, not the critic panel. Exit 0 = pass, 7 = blocked, 8 = not_judged. Swap seats.security_reviewer's model to mock-security-block for the blocking path (this file's default), or to any other name (e.g. mock-security-clean) for the passing path - see docs/security-review-gate.md. Zero engine changes: this is a config-only chain built entirely from existing seat kinds and the existing security_review flag.",
|
|
4
|
+
"maxRounds": 1,
|
|
5
|
+
"criteria": [
|
|
6
|
+
"The artifact under review is present as the resumed external stage's content.",
|
|
7
|
+
"The final security-review gate ran and recorded a gate verdict."
|
|
8
|
+
],
|
|
9
|
+
"seats": {
|
|
10
|
+
"builder": {
|
|
11
|
+
"provider": "external"
|
|
12
|
+
},
|
|
13
|
+
"critics": [
|
|
14
|
+
{
|
|
15
|
+
"provider": "mock",
|
|
16
|
+
"model": "mock-critic-passer",
|
|
17
|
+
"lab": "mock-passthrough"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"security_reviewer": {
|
|
21
|
+
"provider": "mock",
|
|
22
|
+
"model": "mock-security-block",
|
|
23
|
+
"lab": "mock-security"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"security_review": {
|
|
27
|
+
"enabled": true
|
|
28
|
+
}
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "the-high-council",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"mcpName": "io.github.muad-yasin/the-high-council",
|
|
5
5
|
"description": "The High Council: a multi-model planning harness. One builder, independent critics from other labs, checkable acceptance criteria, a debate on the record, and a hard stop.",
|
|
6
6
|
"type": "module",
|
package/schemas/report-v1.json
CHANGED
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"outcome": {
|
|
84
84
|
"x-stability": "stable",
|
|
85
85
|
"enum": ["consensus", "no_consensus", "degraded"],
|
|
86
|
-
"description": "Verdict class, computed by src/outcome.js from the rest of this file. `degraded` wins:
|
|
86
|
+
"description": "Verdict class, computed by src/outcome.js from the rest of this file. `degraded` wins: a seated lab produced nothing usable (it dropped out, see `dropouts[]`: in a tiered chain this may be a debating seat that never votes), a reviewer abstained, no reviewer was heard, or the round fell short of the quorum - so the run did not have the roster the chain intended. Otherwise `consensus` if passed, else `no_consensus`."
|
|
87
87
|
},
|
|
88
88
|
"lastCritique": {
|
|
89
89
|
"x-stability": "stable",
|
|
@@ -234,7 +234,8 @@
|
|
|
234
234
|
"model": { "type": "string" },
|
|
235
235
|
"verdict": { "enum": ["signed_off", "objected", "passed", "unheard"] },
|
|
236
236
|
"reason_code": { "anyOf": [{ "type": "null" }, { "$ref": "#/$defs/abstentionReason" }] },
|
|
237
|
-
"reasked": { "type": "boolean", "description": "True if the seat was unheard once and asked again this round." }
|
|
237
|
+
"reasked": { "type": "boolean", "description": "True if the seat was unheard once and asked again this round." },
|
|
238
|
+
"carried": { "type": "boolean", "description": "Present and true when the seat was not asked this round: the draft was byte-identical to the last round's, where this seat was heard and clean, and only the unheard seat(s) were asked again (0.7.9). Absent otherwise." }
|
|
238
239
|
}
|
|
239
240
|
},
|
|
240
241
|
"description": "Every critic's verdict in every review round, both sign-off modes. The per-round history that signoff[] (final round only) does not keep."
|
|
@@ -501,6 +502,141 @@
|
|
|
501
502
|
},
|
|
502
503
|
"description": "Present only on chains with argued.enabled: where the 'How this plan was argued' text is, and the check of every id and lab it names against this run's record."
|
|
503
504
|
},
|
|
505
|
+
"criteria_sha256": {
|
|
506
|
+
"x-stability": "experimental",
|
|
507
|
+
"type": "string",
|
|
508
|
+
"pattern": "^[0-9a-f]{64}$",
|
|
509
|
+
"description": "sha256 over the criteria list, each criterion collapsed to one line, order counted (0.8.0). The same fingerprint the HANDOFF.md lock block carries; `council check-lock` compares them."
|
|
510
|
+
},
|
|
511
|
+
"criteria_lints": {
|
|
512
|
+
"x-stability": "experimental",
|
|
513
|
+
"type": "array",
|
|
514
|
+
"description": "Word-level lints over the acceptance criteria, run before any paid review round (0.8.0). Heuristics: they miss a rephrasing and can flag a good criterion. Recorded only: never a stop. [] when clean.",
|
|
515
|
+
"items": {
|
|
516
|
+
"type": "object",
|
|
517
|
+
"required": ["id", "message"],
|
|
518
|
+
"properties": {
|
|
519
|
+
"id": { "enum": ["no-consistency", "presence-heavy", "vague-word"] },
|
|
520
|
+
"message": { "type": "string" },
|
|
521
|
+
"criterion_ids": { "type": "array", "items": { "type": "string" } }
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
"criteria_ids": {
|
|
526
|
+
"x-stability": "experimental",
|
|
527
|
+
"type": "array",
|
|
528
|
+
"items": {
|
|
529
|
+
"type": "string"
|
|
530
|
+
},
|
|
531
|
+
"description": "Positional ids for `criteria`, index-aligned: C1, C2, ... (0.8.0)."
|
|
532
|
+
},
|
|
533
|
+
"missing_criteria": {
|
|
534
|
+
"x-stability": "experimental",
|
|
535
|
+
"type": "array",
|
|
536
|
+
"description": "Sign-offs whose criteria table left criteria out (0.8.0). Recorded only: no verdict, prompt or stop reads it. [] when there were none. A reply with no table at all is not listed.",
|
|
537
|
+
"items": {
|
|
538
|
+
"type": "object",
|
|
539
|
+
"required": [
|
|
540
|
+
"round",
|
|
541
|
+
"lab",
|
|
542
|
+
"criterion_ids"
|
|
543
|
+
],
|
|
544
|
+
"properties": {
|
|
545
|
+
"round": {
|
|
546
|
+
"type": "integer"
|
|
547
|
+
},
|
|
548
|
+
"lab": {
|
|
549
|
+
"type": "string"
|
|
550
|
+
},
|
|
551
|
+
"criterion_ids": {
|
|
552
|
+
"type": "array",
|
|
553
|
+
"items": {
|
|
554
|
+
"type": "string"
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
"table_rows": {
|
|
558
|
+
"type": "integer"
|
|
559
|
+
},
|
|
560
|
+
"criteria_total": {
|
|
561
|
+
"type": "integer"
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
"cut_despite_support": {
|
|
567
|
+
"x-stability": "experimental",
|
|
568
|
+
"type": "array",
|
|
569
|
+
"description": "Proposals the plan cut although another lab supported them in the debate (0.8.0). Derived from proposals[] and debate.posts[]; present only when the run had both.",
|
|
570
|
+
"items": {
|
|
571
|
+
"type": "object",
|
|
572
|
+
"required": [
|
|
573
|
+
"id",
|
|
574
|
+
"supporters"
|
|
575
|
+
],
|
|
576
|
+
"properties": {
|
|
577
|
+
"id": {
|
|
578
|
+
"type": "string"
|
|
579
|
+
},
|
|
580
|
+
"title": {},
|
|
581
|
+
"author_lab": {
|
|
582
|
+
"type": [
|
|
583
|
+
"string",
|
|
584
|
+
"null"
|
|
585
|
+
]
|
|
586
|
+
},
|
|
587
|
+
"supporters": {
|
|
588
|
+
"type": "array",
|
|
589
|
+
"items": {
|
|
590
|
+
"type": "string"
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
"objectors": {
|
|
594
|
+
"type": "array",
|
|
595
|
+
"items": {
|
|
596
|
+
"type": "string"
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
"note": {
|
|
600
|
+
"type": "string"
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
"disagreement_map": {
|
|
606
|
+
"x-stability": "experimental",
|
|
607
|
+
"type": "array",
|
|
608
|
+
"description": "One row per review round: each lab's verdict and the counts (0.8.0). Derived from panelVerdicts[]. A verdict marked `(carried)` was reused on an unchanged draft.",
|
|
609
|
+
"items": {
|
|
610
|
+
"type": "object",
|
|
611
|
+
"required": [
|
|
612
|
+
"round",
|
|
613
|
+
"labs"
|
|
614
|
+
],
|
|
615
|
+
"properties": {
|
|
616
|
+
"round": {
|
|
617
|
+
"type": "integer"
|
|
618
|
+
},
|
|
619
|
+
"labs": {
|
|
620
|
+
"type": "object",
|
|
621
|
+
"additionalProperties": {
|
|
622
|
+
"type": "string"
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
"signed_off": {
|
|
626
|
+
"type": "integer"
|
|
627
|
+
},
|
|
628
|
+
"objected": {
|
|
629
|
+
"type": "integer"
|
|
630
|
+
},
|
|
631
|
+
"unheard": {
|
|
632
|
+
"type": "integer"
|
|
633
|
+
},
|
|
634
|
+
"passed": {
|
|
635
|
+
"type": "integer"
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
},
|
|
504
640
|
"criteria_kinds": {
|
|
505
641
|
"x-stability": "experimental",
|
|
506
642
|
"type": "array",
|
|
@@ -614,7 +750,8 @@
|
|
|
614
750
|
},
|
|
615
751
|
"passed": { "type": "boolean", "description": "True if the seat stated a pass (declined to give a verdict, with a reason). Not the same as the top-level `passed`." },
|
|
616
752
|
"passReason": { "type": ["string", "null"] },
|
|
617
|
-
"reason_code": { "anyOf": [{ "type": "null" }, { "$ref": "#/$defs/abstentionReason" }] }
|
|
753
|
+
"reason_code": { "anyOf": [{ "type": "null" }, { "$ref": "#/$defs/abstentionReason" }] },
|
|
754
|
+
"seat_index": { "type": "integer", "description": "The seat's index in the chain's seats.critics (0.7.9). A relay panel lists signoff[] in its review order, so array position is not the seat; replay and rematch diffs key on this. Absent on earlier reports." }
|
|
618
755
|
}
|
|
619
756
|
},
|
|
620
757
|
"proposal": {
|
|
@@ -684,14 +821,14 @@
|
|
|
684
821
|
},
|
|
685
822
|
"dropped": {
|
|
686
823
|
"type": "array",
|
|
687
|
-
"description": "Experimental (0.7.8). Debate posts and author replies the stage's filters rejected, one row per stage, lab and reason; [] when none were. Absent in runs made before 0.7.8. Reasons: for stage 'debate' unknown_target, own_proposal, bad_stance, unreadable; for stage 'replies' unknown_target, not_own_proposal, not_posted_on, bad_action, unreadable. An 'unreadable' row counts whole replies that did not parse, not posts.",
|
|
824
|
+
"description": "Experimental (0.7.8). Debate posts and author replies the stage's filters rejected, one row per stage, lab and reason; [] when none were. Absent in runs made before 0.7.8. Reasons: for stage 'debate' unknown_target, own_proposal, bad_stance, unreadable, provider_error; for stage 'replies' unknown_target, not_own_proposal, not_posted_on, bad_action, unreadable, provider_error. An 'unreadable' row counts whole replies that did not parse, not posts; 'provider_error' (0.7.9) counts whole replies the provider ended with stop error, content_filter or refusal on the first try and on its one retry.",
|
|
688
825
|
"items": {
|
|
689
826
|
"type": "object",
|
|
690
827
|
"required": ["stage", "by", "reason", "count"],
|
|
691
828
|
"properties": {
|
|
692
829
|
"stage": { "enum": ["debate", "replies"] },
|
|
693
830
|
"by": { "type": "string", "description": "The lab whose post or reply was dropped." },
|
|
694
|
-
"reason": { "enum": ["unknown_target", "own_proposal", "bad_stance", "not_own_proposal", "not_posted_on", "bad_action", "unreadable"] },
|
|
831
|
+
"reason": { "enum": ["unknown_target", "own_proposal", "bad_stance", "not_own_proposal", "not_posted_on", "bad_action", "unreadable", "provider_error"] },
|
|
695
832
|
"count": { "type": "integer", "minimum": 1 }
|
|
696
833
|
}
|
|
697
834
|
}
|
package/src/api.js
CHANGED
|
@@ -72,9 +72,9 @@ export function price({ chain, cwd = process.cwd(), rounds } = {}) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// The ceiling is never silently off. undefined: the CLI's own default (MAX_USD_PER_RUN, else $7).
|
|
75
|
-
// A positive number: that ceiling. 'none': no ceiling, said explicitly.
|
|
76
|
-
//
|
|
77
|
-
//
|
|
75
|
+
// A positive number: that ceiling. 'none': no ceiling, said explicitly. 0 is refused, because a
|
|
76
|
+
// caller who wrote 0 almost certainly meant "spend nothing", and reading it as "spend without limit"
|
|
77
|
+
// is the costliest possible guess. Since 0.7.9 the CLI and the MCP tools refuse it too.
|
|
78
78
|
function maxUsdArgs(maxUsd) {
|
|
79
79
|
if (maxUsd === undefined) return [];
|
|
80
80
|
if (maxUsd === 'none') return ['--max-usd', 'none'];
|
|
@@ -110,8 +110,12 @@ function runCli(args, { cwd, env, onOutput, signal }) {
|
|
|
110
110
|
};
|
|
111
111
|
child.stdout.on('data', take('stdout'));
|
|
112
112
|
child.stderr.on('data', take('stderr'));
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
// Bug audit 2026-09-28 (area 4 MED-1): an abort rejected on 'error', before the child had exited,
|
|
114
|
+
// so a caller that resumed at once could meet a run still marked running. The abort now settles
|
|
115
|
+
// only on 'close'; any other spawn error rejects at once, as before.
|
|
116
|
+
let aborted = null;
|
|
117
|
+
child.on('error', err => { if (err?.name === 'AbortError') aborted = err; else reject(err); });
|
|
118
|
+
child.on('close', (code, sig) => aborted ? reject(aborted) : resolvePromise({ exitCode: code, signal: sig, outputTail: tail.join('').split('\n').slice(-40).join('\n') }));
|
|
115
119
|
});
|
|
116
120
|
}
|
|
117
121
|
|
|
@@ -120,7 +124,7 @@ function runCli(args, { cwd, env, onOutput, signal }) {
|
|
|
120
124
|
* spend ceiling, or refused by a guard. Resolves in every one of those cases (read `status` and
|
|
121
125
|
* `exitCode`); rejects only when the child process could not be started or was aborted.
|
|
122
126
|
*/
|
|
123
|
-
export async function run({ chain, task, cwd = process.cwd(), maxUsd, rounds, draft, fromRun, context, piiGate, env, onOutput, signal } = {}) {
|
|
127
|
+
export async function run({ chain, task, cwd = process.cwd(), maxUsd, rounds, draft, fromRun, context, piiGate, allowSecretShaped, env, onOutput, signal } = {}) {
|
|
124
128
|
const work = resolve(cwd);
|
|
125
129
|
chainPath(chain, work); // a clear error here beats a CLI usage message
|
|
126
130
|
if (typeof task !== 'string' || !task) throw new TypeError('task: a path to the task file');
|
|
@@ -137,8 +141,15 @@ export async function run({ chain, task, cwd = process.cwd(), maxUsd, rounds, dr
|
|
|
137
141
|
if (piiGate !== 'warn' && piiGate !== 'hard-stop') throw new RangeError(`piiGate: 'warn' or 'hard-stop', got ${JSON.stringify(piiGate)}`);
|
|
138
142
|
args.push('--pii-gate', piiGate);
|
|
139
143
|
}
|
|
140
|
-
|
|
144
|
+
// 0.7.9 outbound key scan: the one override (saved in run.json, so a resume keeps it).
|
|
145
|
+
if (allowSecretShaped === true) args.push('--allow-secret-shaped');
|
|
141
146
|
const runDir = join(work, 'runs', id);
|
|
147
|
+
// Area 4 MED-1: an aborted run's stages stay on disk and can be resumed, so the rejection says
|
|
148
|
+
// which run it was (`runId`, and `runDir` once the folder exists).
|
|
149
|
+
const res = await runCli(args, { cwd: work, env, onOutput, signal }).catch(err => {
|
|
150
|
+
if (err && typeof err === 'object') Object.assign(err, { runId: id, runDir: existsSync(runDir) ? runDir : null });
|
|
151
|
+
throw err;
|
|
152
|
+
});
|
|
142
153
|
return { runId: id, runDir: existsSync(runDir) ? runDir : null, ...res, ...(existsSync(runDir) ? statusOf(runDir) : { status: 'not_started', report: null }) };
|
|
143
154
|
}
|
|
144
155
|
|
|
@@ -146,11 +157,12 @@ export async function run({ chain, task, cwd = process.cwd(), maxUsd, rounds, dr
|
|
|
146
157
|
* Resume a paused run (after its external stage was answered) or one the spend ceiling stopped
|
|
147
158
|
* (pass a higher maxUsd). Stages already on disk replay from disk and cost nothing again.
|
|
148
159
|
*/
|
|
149
|
-
export async function resume({ runDir, cwd = process.cwd(), maxUsd, env, onOutput, signal } = {}) {
|
|
160
|
+
export async function resume({ runDir, cwd = process.cwd(), maxUsd, allowSecretShaped, env, onOutput, signal } = {}) {
|
|
150
161
|
const work = resolve(cwd);
|
|
151
162
|
const dir = resolve(work, runDir ?? '');
|
|
152
163
|
if (!runDir || !existsSync(join(dir, 'run.json'))) throw new Error(`runDir: not a run folder with a run.json: ${dir}`);
|
|
153
|
-
|
|
164
|
+
// Verify pass 2026-09-28 F1(b): continue a run the outbound key scan stopped.
|
|
165
|
+
const res = await runCli(['--resume', dir, ...maxUsdArgs(maxUsd), ...(allowSecretShaped === true ? ['--allow-secret-shaped'] : [])], { cwd: work, env, onOutput, signal });
|
|
154
166
|
return { runId: basename(dir), runDir: dir, ...res, ...statusOf(dir) };
|
|
155
167
|
}
|
|
156
168
|
|
package/src/cache-integrity.js
CHANGED
|
@@ -15,7 +15,11 @@ import { createHash } from 'node:crypto';
|
|
|
15
15
|
|
|
16
16
|
/** A short fingerprint of the inputs a cached stage's validity depends on. */
|
|
17
17
|
export function fingerprintInputs(taskText, config) {
|
|
18
|
-
|
|
18
|
+
// `summary` is a chain card's display line: no stage reads it, so editing it must not make a
|
|
19
|
+
// resumed run read every finished stage as stale. A config without one hashes exactly as before.
|
|
20
|
+
let forHash = config;
|
|
21
|
+
if (config && typeof config === 'object' && 'summary' in config) { const { summary: _display, ...rest } = config; forHash = rest; }
|
|
22
|
+
return createHash('sha256').update(JSON.stringify({ taskText, config: forHash })).digest('hex').slice(0, 12);
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
/**
|