pi-gauntlet 7.18.1 → 7.19.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/CHANGELOG.md +6 -0
- package/README.md +2 -2
- package/agents/spec-council-applier.md +43 -0
- package/agents/spec-council-synthesizer.md +2 -2
- package/extensions/telemetry.test.ts +42 -0
- package/extensions/telemetry.ts +4 -1
- package/package.json +1 -1
- package/skills/brainstorming/reference/documentation-impact.md +1 -1
- package/skills/brainstorming/reference/spec-finalization.md +2 -2
- package/skills/roasting-the-spec/SKILL.md +54 -30
- package/skills/shape-ticket/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v7.19.0 - 2026-10-19
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Spec council critiques stay in files; a fresh applier edits the spec.** Members and the spec chair return saved-file references, while `spec-council-applier` decides dispositions, edits only the spec, and returns the audit. The applier inherits the main loop's model and thinking unless overridden; the main loop re-reads the spec before the unchanged ratify/revert gate. Ticket-roast members also return file-only output; their chair stays inline. Telemetry accepts inline or saved-file chair clusters and applier, commit-command, or assistant audits with the same completeness, provenance, and schema rules. Failed children without a saved file can still return inline text upstream; fail-closed output remains a pi-cohort follow-up.
|
|
8
|
+
|
|
3
9
|
## v7.18.1 - 2026-10-19
|
|
4
10
|
|
|
5
11
|
### Removed
|
package/README.md
CHANGED
|
@@ -78,7 +78,7 @@ The run's grants, target/scope baseline, repair usage, and poll deadline live in
|
|
|
78
78
|
pi-gauntlet ships three kinds of pieces, layered on top of pi-cohort's dispatch:
|
|
79
79
|
|
|
80
80
|
- **20 skills** - the workflow logic. Fifteen activate automatically when pi sees the matching kind of task, and the workflow skills chain through their gates: `shape-ticket` (creates or repairs one tracker issue per run against a Context/Problem/Idea/Acceptance-Criteria template, gated by an AC integrity check, a cheap council roast, and a single human-confirmed write; model-invocable so other skills and commands can route "file a ticket" to it, the gate still needs your yes), `gatekeep-pr` (model-invocable on an explicit ask that names the PR and the verb; the gates still need your selection - is consent-gated pre-merge verification of a PR against the scope contract at its head - the approved spec's acceptance-criteria dispositions and Design when the PR carries one, else the PR's stated intent; the ticket is cross-checked, never judged here (`check-delivery` owns it) - read-only gathering, verification evidence resolved CI-first (green checks on the exact assessed head count as evidence; a pending commit status that GitHub does not report as blocking the gating actor (`mergeStateStatus` not `BLOCKED`) is not waited for - external-CI commit statuses included - while a running Actions check, an unknown merge state, and every other merge precondition still withhold; the project's verification command runs only as fallback), a rubric-based review, a compact bottom-up report (what the PR delivers, including rows deferred or deviating per spec, PR comments, nits, blockers, then a `mergeable` / `fixable` verdict) and a verb menu whose rows derive from the actor's permissions on the PR; nothing mutates (fixes, pushes, reviews, merges, tracker comments) until you pick a row, except the opt-in `--rebase [base]` sync that rebases, reviews, and lease-pushes the head before verification, or holds the rebased head locally when a conflict stop's scoped tests fail, so the normal `fix` row resolves it before the lease push; after your own merge two opt-in rows post the `AC coverage` block to the ticket or the PR; every terminal menu offers a recommended `cleanup` row that tears down the gate's worktree and branch and runs the overrides file's `## cleanup` steps - run it with `/skill:gatekeep-pr <pr> [--rebase [base]]`), `check-delivery` (model-invocable on an explicit ask that names the ticket and the verb; the gates still need your selection - is a post-merge detective control: proves an issue actually shipped (default-branch landing, delivery target, per-AC evidence) before its tracker status advances; it never writes a terminal status - run it with `/skill:check-delivery <ref>`), `writing-plans`, `roasting-the-spec`, `test-driven-development`, `subagent-driven-development`, `dispatching-parallel-agents`, `verification-before-completion`, `requesting-code-review`, `receiving-code-review`, `using-git-worktrees`, `finishing-a-development-branch`, `forge-skill`, `linear` (reads/searches/comments on/manages Linear tickets via the `linearis` CLI; owns all linearis mechanics and the `## Issue tracker` overrides schema; tracker-facing skills route to it). Five more require explicit entry (`disable-model-invocation: true`): `brainstorming` starts the gated workflow on explicit consent - use `/skill:brainstorming` for reliable discovery, or opt in through reachable explicit prose or a human-selected handoff; after spec approval, downstream planning and implementation still chain automatically. `chase-bug` is human-only bug triage: read-only root-cause discovery to an evidenced verdict menu (real bug -> ticket/brainstorm/hotfix/respond; five negative verdicts), then a gated response to the reporter for addressable origins (GitHub issue / tracker ticket) and a rendered verdict summary otherwise - it never fixes during triage; the hotfix row hands off to `skills/chase-bug/hotfix.md` after the menu - run it with `/skill:chase-bug`. `gauntlet-performance` reads the committed run telemetry (current repo by default, `--dir <path>` adds others) through the parse-only `gauntlet-performance` CLI and answers with one example-led recommendation, 3-5 cornerstone numbers, a council assessment when available, and a menu of at most three actions (render a report file, open the recommendation as a ticket via `shape-ticket`, drill into one run); it writes nothing unless you pick render - run it with `/skill:gauntlet-performance [--dir <path>]... [--since <version>]`. `gauntlet-handoff` ends a session whose flow a fresh session will continue: it invokes pi-cohort's `handoff` skill (`--out <path>` or `--key <name>`, default key = the run worktree's branch with `/` flattened to `-`, default file `<tmpdir>/pi-handoff/<key>.md`), then appends the gauntlet process-state section (phase/plan tracker status) per the shared contract `skills/gauntlet-resume/reference/brief-contract.md` - run it with `/skill:gauntlet-handoff [--out <path> | --key <name>]`. `gauntlet-resume` is the only way back into an interrupted flow from a fresh session: it takes a `gauntlet-handoff` brief (a file path, pasted text, or - with no arguments - a pick from the briefs under `<tmpdir>/pi-handoff/`), a bare worktree that already holds a spec, or a spec tracked on main under a configured spec dir (a spec seed: it creates or reuses the worktree through `using-git-worktrees` and pins the spec), restores phase/plan tracker state through the legal arming sequence (`start brainstorm`, `skip` with `resume:` reasons, `plan_check` before implement-or-later), and never infers approval from artifacts - run it with `/skill:gauntlet-resume [<brief-file> | <spec>.md | <worktree-name-or-path>]`.
|
|
81
|
-
- **
|
|
81
|
+
- **9 subagent personas** - the specialized child agents the skills dispatch via pi-cohort: `implementer`, `code-reviewer`, `spec-reviewer`, `conformance-reviewer`, `spec-summarizer`, `plan-writer`, `spec-council-member`, `spec-council-synthesizer`, `spec-council-applier`. See [doc/personas.md](./doc/personas.md) for what each one does and why its permissions are scoped the way they are.
|
|
82
82
|
- **4 runtime extensions** - the enforcement layer. `plan-tracker` and `phase-tracker` are tools skills call to track progress (with a TUI widget); `verify-before-ship` is a hook that warns if you push or open a PR without a passing test run since your last edit; a phase-tracker flow guard reminds on implement-phase commits missing spec/code review. In a brainstorming-entered flow, phase-tracker rejects `implement` or `verify` completion while tracker tasks remain pending or in progress; see [its configuration reference](./doc/configuration.md#phase-tracker). phase-tracker also registers `plan_check`, which verifies a plan against its spec and against the grammar in [skills/writing-plans/reference/plan-contract.md](./skills/writing-plans/reference/plan-contract.md), including that each task's `Tests:` commands are selective and never the full suite; a pass stamps the plan for implementation. `telemetry` records one YAML record per gauntlet run (phase timing, models, personas, gate/fix rounds, diff at ship) that ships in the squash beside the spec - it is written only inside a brainstorming-entered flow, kept out of history until `finishing-a-development-branch` seals it once with `gauntlet-telemetry-seal` (a `telemetry:` commit under git; the working-copy snapshot in a plain jj workspace) - and blocks a brainstorm `write` into an already-shipped spec; see [its configuration reference](./doc/configuration.md#telemetry). See [doc/configuration.md](./doc/configuration.md) for the settings each one reads.
|
|
83
83
|
|
|
84
84
|
pi-gauntlet is **opinionated**: it recommends this pipeline for non-trivial changes, but starts `brainstorming` only after explicit user consent. Enforcement is opt-in by entry, not ambient: once brainstorming starts a flow, the phase-tracker extension mechanically blocks a phase from closing before its gate runs, and warns once if the main loop writes code during implement (subagents own implement-phase edits). A change made *without* entering the flow (a typo, a formatting run, a dependency bump - see "When to use / when NOT to use") is not gated; the discipline of routing real work through the pipeline is a convention the tooling supports, not a trap it springs on every edit.
|
|
@@ -108,7 +108,7 @@ Run by a human against pi-cohort >= 7.1.0, before a pi-gauntlet release claims t
|
|
|
108
108
|
| Term | Meaning |
|
|
109
109
|
| --- | --- |
|
|
110
110
|
| Gate | A machine-enforced checkpoint between phases (e.g. within a brainstorming-entered flow, `complete verify` is blocked until conformance review has run). Not a suggestion. |
|
|
111
|
-
| Spec council | Multi-model critique of the spec before you see it (`roasting-the-spec`); members
|
|
111
|
+
| Spec council | Multi-model critique of the spec before you see it (`roasting-the-spec`); members and chair return saved-file references, and a fresh applier inherits the main loop's model and thinking unless overridden, edits only the spec, and returns the audit. The main loop checks structure without ingesting member/chair findings, re-reads the spec, and hands it to the unchanged user gate to ratify or revert. Members flag unrelated extras or sufficient in-scope simplifications (`over-spec`); every member closes with a `lean:` line - "nothing to cut" is a first-class answer - and the chair tallies them (`lean: <k> of <n> members found nothing to cut`). Falls back to a single-model critique if no council is configured. |
|
|
112
112
|
| Conformance gate | The closing check: does the delivered code + docs match your *original prompt*, not the derived plan? Compatible executable recommendations auto-fix first; anything still open renders as a numbered decision brief - one item per decision, the problem in plain words first, lettered options each with a one-line consequence, and `Recommended: <letter> - <reason>` or `No recommendation - pick one`. Reply with one line per item (`1. B`), or bare `1` to take every recommendation (no-recommendation items are re-asked by number); a current `CONFORMS` / no-concerns handoff goes straight to branch options with no extra sign-off. |
|
|
113
113
|
| Wave | A batch of plan tasks that don't touch the same files, dispatched to implementers in parallel. |
|
|
114
114
|
| Overrides file | `.pi/gauntlet-overrides.md` - where you put project-specific detail the generic skills don't know (CI command, worktree wrapper, routing rules). |
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-council-applier
|
|
3
|
+
description: Applies a spec-council chair report to the spec under review and returns the audit. Dispatched by the roasting-the-spec skill; not for direct dispatch.
|
|
4
|
+
tools: read, grep, find, ls, bash, edit, write
|
|
5
|
+
defaultContext: fresh
|
|
6
|
+
inheritProjectContext: true
|
|
7
|
+
inheritSkills: false
|
|
8
|
+
completionGuard: false
|
|
9
|
+
systemPromptMode: replace
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
You are the spec council's scope advocate and executor. Apply the chair's adjudicated clusters to the supplied spec so the user can ratify the result at the gate.
|
|
13
|
+
|
|
14
|
+
Return only the audit as your final message: optional `Coverage:` copied from the task, followed by `Applied:`, `Deferred:`, and `Rejected:` lists, in that order. Emit exactly one disposition per cluster. Copy `[<severity>]` and `raised-by: [...]` verbatim from each cluster line. Use this line grammar:
|
|
15
|
+
|
|
16
|
+
- `Applied: [<severity>] <cluster> - raised-by: [<slugs>] -> <edit> (grounded: <member probe>)` for a grounded application.
|
|
17
|
+
- `Applied: [<severity>] <cluster> - raised-by: [<slugs>] -> <edit> (probed: <check> - <result>)` for a confirmed hypothesis.
|
|
18
|
+
- `Applied: [<severity>] <cluster> - raised-by: [<slugs>] -> open question (<not found | inconclusive: <check> | timed out: <check> | contradicted: <result>>)` for unresolved data.
|
|
19
|
+
- `Deferred: [<severity>] <cluster> - raised-by: [<slugs>] -> <where it belongs>`.
|
|
20
|
+
- `Rejected: [<severity>] <cluster> - raised-by: [<slugs>] -> <one-line reason>`.
|
|
21
|
+
|
|
22
|
+
Use `Applied: none`, `Deferred: none`, or `Rejected: none` for an empty list. Emit no acknowledgment or second report; the audit is not a spec section.
|
|
23
|
+
|
|
24
|
+
## Procedure
|
|
25
|
+
|
|
26
|
+
1. Consume the task's problem statement, spec path, chair file path, usable member file paths, worktree path, optional coverage line, and `DOCUMENTATION_IMPACT_GUIDELINE` path. Treat `Human input (verbatim; off-limits for over-spec)` as the authoritative scope boundary. Consume fetched ticket body and comments from `## External context`, with the ticket reference, when supplied. Preserve the supplied not-an-external-reference sentence verbatim: the portable documentation-impact citation names the supplied guideline, not a consumer doc. Read the supplied guideline for documentation-impact decisions.
|
|
27
|
+
2. Read the chair file and the supplied spec. Decide apply, defer with a destination, or reject with a one-line reason for every cluster on scope grounds against the human input. Never suppress a cluster. Read usable member files only to recover the cited probe of a grounded cluster for its audit line. Never reopen adjudication or weigh member findings again.
|
|
28
|
+
3. Apply the hypothesis rule below, then execute the apply-set. Edit only the supplied spec path. The `**Amend-grant:**` header line is flow machinery owned by the brainstorming gate; never cut, shrink, flag, or edit it.
|
|
29
|
+
4. Return the audit using the opening contract.
|
|
30
|
+
|
|
31
|
+
## Hypothesis rule
|
|
32
|
+
|
|
33
|
+
Treat an untagged cluster as hypothesis. Probe hypothesis clusters that assert data shape, ordering, or semantics (a parsing rule, a field's meaning, a sort or date order, an identity key) before applying their claim. Search once for the artifact or how it is obtained: one `rg --max-count` under `timeout 30` across the supplied worktree and its docs, config, and script directories. Keep the search bounded to those paths.
|
|
34
|
+
|
|
35
|
+
At hand -> perform at most one bounded read-only check: a read, an `rg` over explicit paths, or a project script whose source you read and which only reads local files. Confirmed -> apply as fact.
|
|
36
|
+
|
|
37
|
+
Anything else (not found, inconclusive, timed out, contradicted) -> create `## Open questions` when absent and write one entry per artifact. Include the probe run, outcome, obtain-hint if found, every affected edit it settles, and the settlement path: the user supplies the fact at the gate, or the first plan task that obtains the artifact settles it via brainstorming's amendment path. Never fetch, build, or run the proposed change to obtain the artifact. Route hypotheses that assert nothing about data through ordinary apply/defer/reject dispositions.
|
|
38
|
+
|
|
39
|
+
## External references and over-spec
|
|
40
|
+
|
|
41
|
+
Inline an `external-ref:` cluster only from the human-input block or fetched external context carrying the reference. Otherwise defer it with `-> user supplies at gate`.
|
|
42
|
+
|
|
43
|
+
Execute an applied `over-spec:` cluster by deleting or shrinking the quoted clause and every acceptance-criteria or testing-approach line that exists only for it. Keep the human-input block off-limits for over-spec. End its audit line with `-> cut (was adds: M files / N tests / K ACs)` or `-> shrunk to <replacement> (was adds: ...)`.
|
|
@@ -12,7 +12,7 @@ systemPromptMode: replace
|
|
|
12
12
|
|
|
13
13
|
You are the chair of a spec review council. One or more members, each on a different model, have independently critiqued the same spec and written their critiques to files. You did not write the spec and you are not defending it — you weigh the members' testimony.
|
|
14
14
|
|
|
15
|
-
You receive the problem statement, the path to the spec, and the explicit paths to the member critique files.
|
|
15
|
+
You receive the problem statement, the path to the spec, and the explicit paths to the member critique files. Read the member critique files directly from the explicit paths supplied in your task. Do **not** run find/grep/ls to discover critique files; you are given every path. Use read/grep/find/ls only to check a contested claim against the codebase when members disagree on a fact - and only when your dispatching task permits codebase access. Bound any such check: `rg` (respects `.gitignore`) over recursive `grep`, explicit paths (never a repository root), `--max-count`, and `timeout`/`gtimeout` when available; a check that cannot be bounded or times out is resolved on testimony weight instead, noted as unverified - never run unbounded.
|
|
16
16
|
|
|
17
17
|
Your job has two parts:
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@ Your job has two parts:
|
|
|
24
24
|
You do not decide what gets applied to the spec — that is the author's and the user's call. You produce one consolidated, conflict-free report.
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
Write the entire identical report below to the path named by the injected `**Output:**` instruction; an acknowledgment or partial file replaces the report, so write the complete report, not an acknowledgment or partial content. Without an injected output path, emit exactly this markdown and nothing else:
|
|
28
28
|
|
|
29
29
|
```
|
|
30
30
|
consensus: <one-line overall verdict, e.g. needs-work — 2 of 3 members flagged blockers>
|
|
@@ -590,6 +590,48 @@
|
|
|
590
590
|
assert.deepEqual(h.readRecord().derived.council, EXPECTED_COUNCIL);
|
|
591
591
|
assert.deepEqual(h.readRecord().derived.personas["spec-council-member"], { dispatches: 3, models: ["p/alpha:xhigh", "p/beta:high"], tokens: { input: 3, output: 0, cache_read: 0, cache_write: 0, cost: 0 } });
|
|
592
592
|
});
|
|
593
|
+
for (const source of ["saved report", "inline report", "missing report"] as const) {
|
|
594
|
+
test(`council chair artifact: ${source}`, async () => {
|
|
595
|
+
const h = await boundInBrainstorm();
|
|
596
|
+
const chairPath = join(h.root, "chair.md");
|
|
597
|
+
if (source !== "missing report") writeFileSync(chairPath, source === "inline report" ? "consensus: sound\nclusters:\nresolved:\n" : CHAIR_TEXT);
|
|
598
|
+
await h.emit("tool_result", memberBatch());
|
|
599
|
+
await h.emit("tool_result", subagentResult([
|
|
600
|
+
{ agent: "spec-council-synthesizer", exitCode: 0, model: "p/chair:medium", savedOutputPath: chairPath, usage: usage(1) },
|
|
601
|
+
], source === "inline report" ? CHAIR_TEXT : `Output saved to: ${chairPath}`));
|
|
602
|
+
assert.equal(h.readFileCalls.filter((p) => p === chairPath).length, source === "inline report" ? 0 : 1);
|
|
603
|
+
await h.emit("message_end", assistant(AUDIT_TEXT));
|
|
604
|
+
assert.deepEqual(h.readRecord().derived.council, source === "missing report" ? undefined : EXPECTED_COUNCIL);
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
test("council accepts the applier audit before conflicting commit and chat audits", async () => {
|
|
608
|
+
const h = await boundInBrainstorm();
|
|
609
|
+
await h.emit("tool_result", memberBatch());
|
|
610
|
+
await h.emit("tool_result", chairResult());
|
|
611
|
+
await h.emit("tool_result", subagentResult([{ agent: "spec-council-applier", exitCode: 0, model: "p/applier", usage: usage(1) }], AUDIT_TEXT));
|
|
612
|
+
assert.deepEqual(h.readRecord().derived.council, EXPECTED_COUNCIL);
|
|
613
|
+
const conflictingAudit = AUDIT_TEXT.replace("Applied:", "Deferred:").replace("Deferred: none", "Applied: none");
|
|
614
|
+
await h.bash("c1", HEREDOC_COMMIT(conflictingAudit));
|
|
615
|
+
assert.deepEqual(h.readRecord().derived.council, EXPECTED_COUNCIL);
|
|
616
|
+
await h.emit("message_end", assistant(conflictingAudit));
|
|
617
|
+
assert.deepEqual(h.readRecord().derived.council, EXPECTED_COUNCIL);
|
|
618
|
+
});
|
|
619
|
+
test("council ignores a failed applier audit and records different dispositions from its successful retry", async () => {
|
|
620
|
+
const h = await boundInBrainstorm();
|
|
621
|
+
await h.emit("tool_result", memberBatch());
|
|
622
|
+
await h.emit("tool_result", chairResult());
|
|
623
|
+
await h.emit("tool_result", { ...subagentResult([{ agent: "spec-council-applier", exitCode: 1, usage: usage(1) }], AUDIT_TEXT), isError: true });
|
|
624
|
+
assert.equal(h.readRecord().derived.council, undefined);
|
|
625
|
+
const retryAudit = AUDIT_TEXT.replace("Applied:", "Deferred:").replace("Deferred: none", "Applied: none");
|
|
626
|
+
await h.emit("tool_result", subagentResult([{ agent: "spec-council-applier", exitCode: 0, usage: usage(1) }], retryAudit));
|
|
627
|
+
assert.deepEqual(h.readRecord().derived.council, {
|
|
628
|
+
...EXPECTED_COUNCIL,
|
|
629
|
+
members: {
|
|
630
|
+
...EXPECTED_COUNCIL.members,
|
|
631
|
+
"p/alpha:xhigh": { ...EXPECTED_COUNCIL.members["p/alpha:xhigh"], applied: counts(), unique_applied: counts(), deferred: counts(1) },
|
|
632
|
+
},
|
|
633
|
+
});
|
|
634
|
+
});
|
|
593
635
|
test("council defaults missing chair model and survives unrelated result before audit", async () => {
|
|
594
636
|
const h = await boundInBrainstorm();
|
|
595
637
|
await h.emit("tool_result", memberBatch());
|
package/extensions/telemetry.ts
CHANGED
|
@@ -650,8 +650,11 @@
|
|
|
650
650
|
const chair = ((councilPending ??= { memberResults: [] }).chair ??= { model: "unknown", dispatches: 0 });
|
|
651
651
|
if (typeof r.model === "string") chair.model = r.model;
|
|
652
652
|
chair.dispatches += 1;
|
|
653
|
-
const parsed = parseChairReport(textOf(content))
|
|
653
|
+
const parsed = parseChairReport(textOf(content))
|
|
654
|
+
?? (typeof r.savedOutputPath === "string" ? parseChairReport(deps.fs.readFile(r.savedOutputPath) ?? "") : null);
|
|
654
655
|
if (parsed) chair.clusters = parsed.clusters;
|
|
656
|
+
} else if (r.agent === "spec-council-applier" && r.exitCode === 0) {
|
|
657
|
+
onCouncilAudit(textOf(content));
|
|
655
658
|
}
|
|
656
659
|
}
|
|
657
660
|
};
|
package/package.json
CHANGED
|
@@ -123,7 +123,7 @@ Doc updates ship in the same commit as the code and the conformance gate verifie
|
|
|
123
123
|
Keep this list in sync with the skills that cite this doc:
|
|
124
124
|
|
|
125
125
|
- `brainstorming` section 6 and `brainstorming/reference/spec-finalization.md` self-review and worker dispatch context.
|
|
126
|
-
- `roasting-the-spec` member and
|
|
126
|
+
- `roasting-the-spec` member, chair, and applier dispatch context.
|
|
127
127
|
- `brainstorming/reference/amendment-surface.md` amendment-review dispatch context.
|
|
128
128
|
- `writing-plans` - sources doc-update tasks from the spec's Documentation
|
|
129
129
|
impact section.
|
|
@@ -49,7 +49,7 @@ The first four are the inline **lint**: run them here and fix what they surface.
|
|
|
49
49
|
|
|
50
50
|
Before dispatching the worker below, resolve `documentation-impact.md` relative to this loaded reference as one absolute `<DOCUMENTATION_IMPACT_GUIDELINE>` path value. Pass that value in the worker task; do not add it to the spec.
|
|
51
51
|
|
|
52
|
-
After the inline lint and before the user review gate, **brainstorming owns the critique-pass gate**; council **apply mechanics** live in `/skill:roasting-the-spec` (single source of truth - link, don't restate). Resolve the council with `gauntlet_setting({ key: "specCouncil" })` - the tool returns the merged (repo-over-preset) value as `{ verdict, members, chair, malformed, warning, errors }`. **Do not** hand-roll a settings read. When `verdict` is `"council"`, the council *is* the critique pass - invoke `/skill:roasting-the-spec` automatically (no offer, no prompt), passing `members`/`chair`; also pass the verbatim human input (the original prompt, any ticket AC snapshot - the raw rows under the gather draft's `## Ticket acceptance criteria (verbatim)` heading, never the spec's section, which holds the author's dispositions - and, for every question that offered a disposition (the cut question and the unmatched-group question in `ticket-acceptance.md`), the full question and the user's answer) - roasting-the-spec forwards it to members and
|
|
52
|
+
After the inline lint and before the user review gate, **brainstorming owns the critique-pass gate**; council **apply mechanics** live in `/skill:roasting-the-spec` (single source of truth - link, don't restate). Resolve the council with `gauntlet_setting({ key: "specCouncil" })` - the tool returns the merged (repo-over-preset) value as `{ verdict, members, chair, malformed, warning, errors }`. **Do not** hand-roll a settings read. When `verdict` is `"council"`, the council *is* the critique pass - invoke `/skill:roasting-the-spec` automatically (no offer, no prompt), passing `members`/`chair`; also pass the verbatim human input (the original prompt, any ticket AC snapshot - the raw rows under the gather draft's `## Ticket acceptance criteria (verbatim)` heading, never the spec's section, which holds the author's dispositions - and, for every question that offered a disposition (the cut question and the unmatched-group question in `ticket-acceptance.md`), the full question and the user's answer) - roasting-the-spec forwards it to members, chair, and applier as the `Human input (verbatim; off-limits for over-spec)` block; its dispatched applier applies the spec edits and supplies the returned audit (Applied/Deferred/Rejected). When `verdict` is `"worker"`, dispatch the worker below. If `malformed` is true or `errors` is non-empty, emit the `warning`/error as one line, then branch strictly on `verdict` - `malformed` can accompany *either* verdict (e.g. a bad `chair` with valid `members` still returns `council`), so never infer the worker path from `malformed` alone. If `gauntlet_setting` is unavailable, stop and report - never fall back to a manual bash/JSON settings merge. The already-applied council edits (or the worker's in-place fixes) ride in the same worktree commit. The conceptual precedence rule lives in `../../verification-before-completion/reference/settings-precedence.md`.
|
|
53
53
|
|
|
54
54
|
When `verdict` is `"worker"`, dispatch one fresh `worker` that applies the scope + ambiguity checks and fixes them in place:
|
|
55
55
|
|
|
@@ -88,7 +88,7 @@ subagent({ agent: "spec-summarizer", context: "fresh", async: false, cwd: "<abs
|
|
|
88
88
|
|
|
89
89
|
`<SUMMARY_PATH>` above is a placeholder in the dispatch object; it means substitute the value of the shell variable `$SUMMARY_PATH` set above. The steps below use `$SUMMARY_PATH` (the shell form) once the value is in hand.
|
|
90
90
|
|
|
91
|
-
Then commit the spec - staging any predecessor spec edited per [Marking superseded specs](superseding.md) alongside it; a change request at the gate that renames, materially revises, or drops the spec also reconciles the predecessor's banner before recommitting. This commit is **unconditional**: the summary is only a gate aid, so a degraded or missing summary never blocks it. Commit with the message on stdin through a quoted heredoc - the only permitted form, so audit lines carrying backticks or `$` land unchanged and each starts a line (telemetry
|
|
91
|
+
Then commit the spec - staging any predecessor spec edited per [Marking superseded specs](superseding.md) alongside it; a change request at the gate that renames, materially revises, or drops the spec also reconciles the predecessor's banner before recommitting. This commit is **unconditional**: the summary is only a gate aid, so a degraded or missing summary never blocks it. Commit with the message on stdin through a quoted heredoc - the only permitted form, so audit lines carrying backticks or `$` land unchanged and each starts a line (telemetry accepts the applier result, this commit command, or assistant text; the first parsed audit wins):
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
94
|
git -C <abs worktree path> add -- <spec path> [<predecessor path>] && git -C <abs worktree path> commit -q -F - -- <spec path> [<predecessor path>] <<'EOF'
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: roasting-the-spec
|
|
3
|
-
description: Use after writing a spec
|
|
3
|
+
description: Use after writing a spec when the resolved piGauntlet.specCouncil members list is non-empty. Auto-dispatched by /skill:brainstorming as its configured critique pass with a fresh-context applier executor before the spec review gate.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Roasting the Spec (Spec Council)
|
|
7
7
|
|
|
8
8
|
## Overview
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Run a multi-model critique pass for a freshly written spec. Each council **member** runs on a different model and critiques independently; the neutral **chair** consolidates and adjudicates disagreements. Dispatch a fresh-context **applier** inheriting the main loop's model and thinking to decide dispositions and edit the spec, returning only the audit. Hand the result to the **user** to ratify (or revert) at brainstorming's single gate.
|
|
11
11
|
|
|
12
12
|
Auto-dispatched from `/skill:brainstorming` as the critique pass, after the inline lint and before the user review gate, **only when a council is configured** (`members` non-empty). brainstorming owns that gate; when no council is configured it runs a single fresh-`worker` critique instead and does not invoke this skill.
|
|
13
13
|
|
|
@@ -19,7 +19,8 @@ This skill may read anything and edit **only** the spec under `doc/specs/`. It d
|
|
|
19
19
|
|
|
20
20
|
- **Members** — independent witnesses. One per configured model, fresh context, read-only.
|
|
21
21
|
- **Chair** — judge of the testimony. Fresh context (never saw the spec authored); consolidates and resolves member-vs-member conflicts. Final say on conflicts; no say on what gets applied.
|
|
22
|
-
- **
|
|
22
|
+
- **Applier** - advocate and executor, fresh context, main loop's model and thinking. Decides apply / defer / reject on scope grounds, probes claims, edits the spec, and returns every disposition in the audit.
|
|
23
|
+
- **Parent (you)** - dispatch, mechanical structural checks, spec reread, cleanup, and gate handoff. Ingest only the applier audit, never member findings or the chair report.
|
|
23
24
|
- **User** — sole jury. Ratifies (or reverts) the finished spec at brainstorming's one gate — after the apply, not before.
|
|
24
25
|
|
|
25
26
|
## Configuration and gating
|
|
@@ -44,7 +45,7 @@ brainstorming owns the gate: it resolves this config via `gauntlet_setting`, emi
|
|
|
44
45
|
|
|
45
46
|
## The council run
|
|
46
47
|
|
|
47
|
-
Resolve `../brainstorming/reference/documentation-impact.md` relative to this loaded skill as one absolute `<DOCUMENTATION_IMPACT_GUIDELINE>` path value. Pass that value in every member and
|
|
48
|
+
Resolve `../brainstorming/reference/documentation-impact.md` relative to this loaded skill as one absolute `<DOCUMENTATION_IMPACT_GUIDELINE>` path value. Pass that value in every member, chair, and applier task below; do not add it to the spec.
|
|
48
49
|
|
|
49
50
|
### 1 — Fan out to members
|
|
50
51
|
|
|
@@ -69,7 +70,8 @@ subagent({
|
|
|
69
70
|
task: "Problem statement: <the problem the spec addresses, from its Context section and the user's stated intent>.\n" +
|
|
70
71
|
"Human input (verbatim; off-limits for over-spec):\n```\n<original prompt>\n<ticket AC snapshot, if any>\n<questionary answers that changed scope>\n```\n" +
|
|
71
72
|
"Read the spec at <abs path to doc/specs/...>. The portable citation `reference/documentation-impact.md` in the spec is the pi-gauntlet guideline at <DOCUMENTATION_IMPACT_GUIDELINE>, not a consumer doc; do not flag it as an external reference. The `**Amend-grant:**` header line is flow machinery owned by the brainstorming gate; never cut, shrink, flag, or edit it. Verify the spec's load-bearing claims against the codebase, bounded per your verification-hygiene rules (rg, explicit paths, timeout 30). Critique it on your five axes and emit your template.",
|
|
72
|
-
output: "<tmpdir>/member-" + i + "-" + slug(model) + ".md"
|
|
73
|
+
output: "<tmpdir>/member-" + i + "-" + slug(model) + ".md",
|
|
74
|
+
outputMode: "file-only"
|
|
73
75
|
}))
|
|
74
76
|
})
|
|
75
77
|
```
|
|
@@ -82,13 +84,15 @@ The `Human input (verbatim; off-limits for over-spec)` block is supplied by the
|
|
|
82
84
|
|
|
83
85
|
**Usable-critique test (mechanical structural probe).** After the fanout returns - success or failure of the tool call itself - probe the expected output paths on disk; judge by files, not by the tool result's failed/succeeded labels (a killed member may have written a usable critique first). A member file is usable iff it is non-empty AND contains a `^verdict:\s*(sound|needs-work|unsound)` line, an `^addresses-problem:` line, and a `^lean:` line. A `findings:` header with zero bullets is a valid, usable sound critique. Existence plus header regex only - never read or weigh findings content.
|
|
84
86
|
|
|
85
|
-
**Targeted retry.** Members whose file is missing or not usable are re-dispatched **once**, together, in a second foreground parallel call carrying `async: false` and the same `control` block. Reuse the complete initial task verbatim
|
|
87
|
+
**Targeted retry.** Members whose file is missing or not usable are re-dispatched **once**, together, in a second foreground parallel call carrying `async: false` and the same `control` block. Reuse the complete initial task verbatim, including per-task `outputMode: "file-only"`. Use fresh output paths that preserve the `member-<i>-<slug>` basename under a `retry/` subdir of the same temp dir (the chair recovers `raised-by` attribution from that filename pattern). Await its terminal result. Members with usable files are never re-run.
|
|
88
|
+
|
|
89
|
+
Override the harness's "Read this file if needed" invitation: run only the structural probe; never ingest member findings or the chair report. Upstream nonzero/save-error exception: with no saved file, inline child text can still escape `file-only` (`attempt-finalization.ts:285-287`, `single-output.ts:193-203`); do not read it. Fail-closed child failure output is a pi-cohort follow-up, not a guarantee implemented here.
|
|
86
90
|
|
|
87
91
|
**Quorum.** At least one usable file after retry -> dispatch the chair over the usable files only (next section). Zero usable files -> abort the council, say so, and return to the user gate.
|
|
88
92
|
|
|
89
93
|
### 2 — Synthesize and adjudicate
|
|
90
94
|
|
|
91
|
-
Dispatch the chair once. It reads the member files (not you), the spec, and the problem statement, and
|
|
95
|
+
Dispatch the chair once. It reads the member files (not you), the spec, and the problem statement, and writes one consolidated, conflict-resolved report to its output file. Judge only the file's structure; route its findings to the applier.
|
|
92
96
|
|
|
93
97
|
```
|
|
94
98
|
subagent({
|
|
@@ -97,10 +101,11 @@ subagent({
|
|
|
97
101
|
model: <chair from config, else omit to inherit>,
|
|
98
102
|
cwd: "<abs worktree path>",
|
|
99
103
|
control: { needsAttentionAfterMs: 300000, inFlightSilenceCeilingMs: 600000, inFlightSilenceKillMs: 900000 },
|
|
100
|
-
|
|
104
|
+
output: "<tmpdir>/chair.md",
|
|
105
|
+
outputMode: "file-only",
|
|
101
106
|
task: "Problem statement: <paste>. Spec: <abs path>.\n" +
|
|
102
107
|
"Human input (verbatim; off-limits for over-spec):\n```\n<the same block passed to members>\n```\n" +
|
|
103
|
-
"Member critiques (
|
|
108
|
+
"Member critiques (explicit usable paths; read these files directly):\n" +
|
|
104
109
|
usableMemberPaths.join("\n") + "\n" +
|
|
105
110
|
"Coverage: <N> of <M> members reported<; <slug>: <one-line reason> per missing member>.\n" +
|
|
106
111
|
"The portable citation `reference/documentation-impact.md` in the spec is the pi-gauntlet guideline at <DOCUMENTATION_IMPACT_GUIDELINE>, not a consumer doc; do not flag it as an external reference. The `**Amend-grant:**` header line is flow machinery owned by the brainstorming gate; never cut, shrink, flag, or edit it.\n" +
|
|
@@ -110,47 +115,66 @@ subagent({
|
|
|
110
115
|
|
|
111
116
|
The chair runs one long foreground single-turn synthesis; await its terminal result before applying findings. The control block sets an effective silence-kill of max(900s, 600+300) = 900s. Margin rationale: one observed healthy chair turn ran 506s of silence, so a 600s kill would leave under 2 minutes of margin - the chair gets 900s. In the coverage line, use pi-cohort's kill diagnostic as the reason when present (e.g. "Likely wedged in a tool call"), else "no output produced"; omit per-member reasons at full coverage. With one usable member, use singular wording ("synthesize the single member critique").
|
|
112
117
|
|
|
113
|
-
List the exact member paths in the task text.
|
|
118
|
+
List the exact member paths in the task text. Single-mode dispatch ignores `reads`; the explicit paths are the chair's inputs.
|
|
119
|
+
|
|
120
|
+
A chair synthesis is usable iff `<tmpdir>/chair.md` exists, is non-empty, and contains a `^consensus:` line and a `^lean:` line. Check existence and header regex mechanically, not report content or tool labels. If the configured `chair` model is unreachable, retry once with the inherited model; a wedge-killed or unusable chair retries once with the same model. Each retry remains foreground with top-level `async: false`. Reuse the complete initial task verbatim. Await its terminal result. Second failure -> abort the council, say so, and return to the user gate.
|
|
114
121
|
|
|
115
|
-
|
|
122
|
+
### 3 - Dispatch the applier and validate mechanically
|
|
116
123
|
|
|
117
|
-
|
|
124
|
+
Snapshot the spec and dirty-path set before dispatch:
|
|
118
125
|
|
|
119
|
-
|
|
126
|
+
```bash
|
|
127
|
+
cp <spec> <tmpdir>/spec.before.md
|
|
128
|
+
git -C <wt> status --porcelain --untracked-files=all > <tmpdir>/status.before
|
|
129
|
+
```
|
|
120
130
|
|
|
121
|
-
-
|
|
122
|
-
- **defer** — out of scope for this spec; name where it belongs. Do not edit the spec.
|
|
123
|
-
- **reject** — one-line reason. Do not edit the spec.
|
|
131
|
+
Dispatch one fresh-context applier in foreground. Leave model and thinking unpinned so `agentOverrides['spec-council-applier'].model` or `.thinking` is honored; otherwise both inherit the main loop. Supply fetched ticket reference + body/comments from the gather draft's `## External context`, or explicit `none`. Include the coverage line only at partial coverage.
|
|
124
132
|
|
|
125
|
-
|
|
133
|
+
```
|
|
134
|
+
subagent({
|
|
135
|
+
agent: "spec-council-applier",
|
|
136
|
+
async: false,
|
|
137
|
+
cwd: "<abs worktree path>",
|
|
138
|
+
control: { needsAttentionAfterMs: 300000, inFlightSilenceCeilingMs: 600000, inFlightSilenceKillMs: 900000 },
|
|
139
|
+
task: "Problem statement: <same problem as members and chair>. Spec: <abs spec path>. Chair report: <tmpdir>/chair.md. Worktree: <abs worktree path>.\n" +
|
|
140
|
+
"Member critiques (probe evidence only):\n" + usableMemberPaths.join("\n") + "\n" +
|
|
141
|
+
"Human input (verbatim; off-limits for over-spec):\n```\n<same block>\n```\n" +
|
|
142
|
+
"External context fetched during brainstorming: <ticket reference + body/comments, or 'none'>.\n" +
|
|
143
|
+
"<Coverage: same partial-coverage line; omit at full coverage>\n" +
|
|
144
|
+
"The portable citation `reference/documentation-impact.md` in the spec is the pi-gauntlet guideline at <DOCUMENTATION_IMPACT_GUIDELINE>, not a consumer doc; do not flag it as an external reference. The `**Amend-grant:**` header line is flow machinery owned by the brainstorming gate; never cut, shrink, flag, or edit it.\n" +
|
|
145
|
+
"Decide and apply the chair's clusters to the spec, then return the audit."
|
|
146
|
+
})
|
|
147
|
+
```
|
|
126
148
|
|
|
127
|
-
|
|
149
|
+
The first action after each applier return is the spec reread in step 4, before validation or any other action. Store the returned audit verbatim at `<tmpdir>/audit.md` for counting. It is the sole findings-bearing result the parent ingests. Require all three labels (`^Applied:`, `^Deferred:`, `^Rejected:`) with `grep -q`, and equality of these mechanical counts (do not print or read chair findings):
|
|
128
150
|
|
|
129
|
-
|
|
151
|
+
```bash
|
|
152
|
+
grep -c 'raised-by:' <tmpdir>/audit.md
|
|
153
|
+
grep -Ec '^- \[(blocker|major|minor)\]' <tmpdir>/chair.md
|
|
154
|
+
```
|
|
130
155
|
|
|
131
|
-
|
|
156
|
+
Accept grep's no-match exit status as a zero count, not a validation failure. Zero clusters and the three `Applied: none`, `Deferred: none`, `Rejected: none` labels is valid.
|
|
132
157
|
|
|
133
|
-
|
|
158
|
+
Killed or unusable result -> restore before retry: copy `<tmpdir>/spec.before.md` over the spec, then retry once with the complete task verbatim. Never stack retries on partial edits. Second failure -> restore again, abort the council, say so, and continue to the gate with the pre-council spec; emit no `Council:` line and no row 3. Clean attributable outside edits on abort too, without fabricating Council counts.
|
|
134
159
|
|
|
135
|
-
|
|
160
|
+
### 4 - Reread and clean attributable edits
|
|
136
161
|
|
|
137
|
-
- `
|
|
138
|
-
- `Applied:` — one line per applied cluster: `Applied: [<severity>] <cluster> — raised-by: [<slugs>] -> <edit> (grounded: <member probe>)`, `... -> <edit> (probed: <check> - <result>)` for a confirmed hypothesis, or `... -> open question (<not found | inconclusive: <check> | contradicted: <result>>)`. Copy `[<severity>]` and `raised-by: [...]` verbatim from the cluster line - telemetry joins on them. No applied cluster -> the single line `Applied: none`. The probe rides on the audit line because member files are removed in section 5.
|
|
139
|
-
- `Deferred:` — one line per deferred cluster, same `[<severity>] <cluster> — raised-by: [<slugs>]` prefix, then `-> <where it belongs>`. None -> `Deferred: none`.
|
|
140
|
-
- `Rejected:` — one line per rejected cluster, same prefix, then `-> <one-line reason>`. None -> `Rejected: none`.
|
|
162
|
+
First `read` the spec from disk, before any other post-applier action, including audit validation, status checks, or a retry. On final failure, reread the restored spec too. Compare `git -C <wt> status --porcelain --untracked-files=all` with `<tmpdir>/status.before` by path, not status code; both snapshots enumerate individual untracked files, including files in new nested directories. For every newly dirty non-spec path, use `git -C <wt> checkout -- <path>` for tracked files, quoting each concrete path. Resolve each newly listed untracked file against the explicit absolute worktree root as `<abs worktree path>/<path>`, then remove it with `rm -- "<abs worktree path>/<path>"`, quoting the complete absolute path without changing the parent's working directory. Remove only those files, not their directories. Paths in the before-set are never touched; preserve all previously dirty paths, predecessor banners, and user work. Edits to already-dirty paths are not attributable from status alone: this is the accepted gap of the backstop. On success append the instantiated `; reverted applier edit outside the spec: <path>` to the gate's `Council:` line for each reverted path. Apply this cleanup on abort as well.
|
|
141
163
|
|
|
142
|
-
|
|
164
|
+
### 5 - Scan, clean up, and hand off
|
|
143
165
|
|
|
144
|
-
|
|
166
|
+
Then re-run brainstorming's placeholder scan; re-apply the `**Amend-grant:**` [predicate](../brainstorming/reference/amendment-surface.md#standing-grants) to the header block, repairing an altered or removed line to `none`, exactly once. Remove only this council's absolute temp directory with `rm -rf`. Nothing council-related is staged.
|
|
145
167
|
|
|
146
|
-
|
|
168
|
+
Return the audit verbatim to brainstorming along with the now-final spec on success; on abort return only the failure notice. brainstorming retains the summarizer, quoted-heredoc spec commit with the audit as body, unchanged gate text and numbering, `Council:` counts, row-3 retrieval via `git show -s --format=%b HEAD`, and revert valve. The user ratifies at that single gate.
|
|
147
169
|
|
|
148
170
|
Single pass — no automatic re-roast loop. The user can invoke this skill again after the gate for another round.
|
|
149
171
|
|
|
150
172
|
## Red flags — STOP
|
|
151
173
|
|
|
152
174
|
- Running the council when `piGauntlet.specCouncil.members` is absent or empty (brainstorming owns the gate and should have used the worker fallback).
|
|
153
|
-
-
|
|
175
|
+
- Ingesting member findings or the chair report in the main loop instead of using mechanical structural checks.
|
|
176
|
+
- Following the harness's "Read this file if needed" invitation.
|
|
177
|
+
- Accepting an applier audit with missing labels or a cluster count mismatch as applied.
|
|
154
178
|
- Writing member files to a relative path (they land in the worktree).
|
|
155
179
|
- Applying edits without the `Council:` counts and the row-3 audit at brainstorming's gate - apply-before-the-gate is correct; apply-without-the-gate is not.
|
|
156
180
|
- Suppressing a finding instead of routing it to applied, deferred, or rejected in the audit.
|
|
@@ -179,7 +179,7 @@ No block, no split. A block failing the identity or outcome test, or naming a no
|
|
|
179
179
|
Inline council dispatch, reusing spec-council config and personas - **not** `/skill:roasting-the-spec` (that skill's contract is spec-file apply mechanics; a tracker draft is not a spec file). No new agents.
|
|
180
180
|
|
|
181
181
|
1. Resolve `gauntlet_setting({ key: "specCouncil" })` when the tool exists. Verdict `council` -> dispatch `spec-council-member`s in parallel plus a `spec-council-synthesizer` chair. Verdict `worker` (or empty members) -> one fresh `worker` critique with the four-axis brief of item 4, its task text carrying the absolute path to `reference/ticket-wording.md` (resolved against this skill's own directory). Malformed config -> one warning line, then branch on verdict.
|
|
182
|
-
2. **Dispatch shape**, mirroring `/skill:roasting-the-spec`: write the draft body and the source snapshot (original ticket + comments, or the create-mode inputs) to absolute temp files under `mktemp -d`; delimit untrusted snapshots as data. The raw ask (create mode) or the original ticket body (repair mode) is also passed as the `Human input (verbatim; off-limits for over-spec)` block. For overlap, include all available mutually exclusive alternatives and the fenced read-only source; do not treat alternatives as split slices. When a split is proposed, the draft artifact holds all N proposed bodies plus their three-line justification blocks (see Split rule) in one file, not a single body. Two separate calls - never fuse members and chair into one chain (a fused chain lets one member failure kill the roast before the chair runs). Call 1: one member fanout with `cwd` = repo root, absolute `output` paths
|
|
182
|
+
2. **Dispatch shape**, mirroring `/skill:roasting-the-spec`: write the draft body and the source snapshot (original ticket + comments, or the create-mode inputs) to absolute temp files under `mktemp -d`; delimit untrusted snapshots as data. The raw ask (create mode) or the original ticket body (repair mode) is also passed as the `Human input (verbatim; off-limits for over-spec)` block. For overlap, include all available mutually exclusive alternatives and the fenced read-only source; do not treat alternatives as split slices. When a split is proposed, the draft artifact holds all N proposed bodies plus their three-line justification blocks (see Split rule) in one file, not a single body. Two separate calls - never fuse members and chair into one chain (a fused chain lets one member failure kill the roast before the chair runs). Call 1: one member fanout with `cwd` = repo root, absolute `output` paths and `outputMode: "file-only"` on every member task and targeted retry, run-level `control: { needsAttentionAfterMs: 60000, inFlightSilenceCeilingMs: 240000, inFlightSilenceKillMs: 300000 }` (sits beside `tasks`, not inside each task; effective silence-kill max(300s, 240+60) = 300s - record all three fields verbatim so a pi-cohort default change cannot stretch the kill). Then probe the member output files on disk with item 7's usable test. Call 2: the inline chair, with explicit usable member paths in its task text, the same control block (`:low` chair turns are short), and task text that (a) forbids repository access - member disagreement on a fact is reported in the synthesis, never verified against the repo - and (b) states coverage: `Coverage: N of M members reported; <slug>: <reason>` (pi-cohort's kill diagnostic when present, else "no output produced"; omit reasons at full coverage; singular wording when one member reported). Member task text: *the draft at `<path>` is the artifact under review; this ticket brief supersedes your spec-axis template - emit the same findings format against the draft; content-only review: the temp files plus the two referenced reference paths (split-axes, ticket-wording) are the entire permitted input - do not read, search, or scan the repository; do not edit any file.* Include the absolute paths to `reference/split-axes.md` and `reference/ticket-wording.md` (both resolved against this skill's own directory) in each member's task text - members run with `cwd` = the consumer repo, where a package-relative path does not resolve.
|
|
183
183
|
3. **Effort: cheap by default.** Append a `:low` thinking suffix to each member's model string at dispatch (this beats the persona's frontmatter `xhigh` pin). Same for the chair: a configured chair string gets any existing suffix replaced with `:low`; an unconfigured chair is dispatched with the main loop's own string, read from `$PI_PROVIDER`/`$PI_MODEL` with the bash tool, plus `:low`. The `worker` fallback carries no thinking pin - it runs at the preset's default. **Full-roast escape:** the user may request a full roast, dispatching all model strings bare/as-configured, restoring the xhigh pins; a full roast reuses the spec-roast control blocks (members `{ needsAttentionAfterMs: 300000, inFlightSilenceCeilingMs: 300000, inFlightSilenceKillMs: 600000 }`, chair `{ needsAttentionAfterMs: 300000, inFlightSilenceCeilingMs: 600000, inFlightSilenceKillMs: 900000 }`) - the 5-minute figures in item 2 are `:low`-only.
|
|
184
184
|
4. **Brief covers four axes**, absorbing the fidelity-review role without a new persona: *fidelity* - compare draft against source intent (original ticket + comments in repair; prompt + answers in create), flag `lost` / `added` / `gap` (unpacking existing claims to satisfy the ticket wording contract is not `added`; contract-conformance findings on Context/Problem/Idea outrank fidelity flags that only object to extra explanation of the same claims); and *quality* - problem framing, AC integrity beyond the deterministic gate, scope, wording, and conformance to the ticket wording contract (reference path provided in every roast brief); and *split soundness* - if the draft proposes a split, test each slice against the split-axes reference (path provided in the task text); an architecture-shaped boundary is reported as a finding line containing the marker `split-axis:` (members keep their existing spec-axis findings template; the marker is a substring flag within it, not a new findings kind), e.g. `- [major] split-axis: <slice> - <why> -> merge`. Members may argue toward one ticket, never propose or endorse a split. And *attribution* - when the Acceptance Criteria section carries `### <repo>` groups, every row sits under the repo that can observe it; a misplaced row is a finding naming the group it belongs to, applied like any other concrete fix; a repo group is never a `split-axis:` finding.
|
|
185
185
|
5. Disposition: unambiguous concrete fixes applied to the draft (one re-pass max); ambiguous findings surfaced at the confirmation gate. Roast edits affect the body draft pre-write only, never posted as a tracker comment, and re-run the deterministic gates (pipeline step 5). Additionally, the parent scans the **usable member output files (item 7's structural test) directly** for lines containing `split-axis:` (substring match), independent of the chair synthesis; any such finding on an actual split (never mutually exclusive overlap alternatives) auto-applies a merge - the split is withdrawn and the draft becomes one ticket with phased AC groups, inside the same one-re-pass budget, and the pre-merge N-body draft is kept alongside: a human re-request of the split at the gate re-presents those N bodies old->new as the approval diff (see the Split rule's sticky override). The chair keeps every other axis; clearing a `split-axis:` finding is not on its path. The same directional rule - toward one ticket, never toward a split - binds the `worker` fallback and the runtime conditional (item 6).
|