ytdb-slate 0.9.0 → 0.10.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 CHANGED
@@ -4,7 +4,9 @@
4
4
 
5
5
  Slate is a thread-weaving orchestration extension for the [pi coding agent](https://pi.dev).
6
6
 
7
- The orchestrator (your main pi session) dispatches **bounded actions** to persistent **worker threads**. Each completed action is compressed by an LLM into an **episode** — a durable, structured record (intent, actions, findings, artifacts, open issues, handoff notes) that the orchestrator composes into further dispatches instead of re-reading raw transcripts. On top of that, Slate injects a mandatory workflow doctrine: research before design, design review, adversarial review, and track review — with optional umbrella **draft-PR publishing** for tracks. An opt-in **model-failover** map adds high availability: when a model API fails, the orchestrator, worker threads, and episode compression each retry once on a configured equal-quality alternative. A second opt-in, **action-level model routing**, gives each dispatched action a model and an effort level chosen to be up to the task and no more, so cost is bounded per action instead of per session.
7
+ The orchestrator (your main pi session) dispatches **bounded actions** to persistent **worker threads**. Each completed action is compressed by an LLM into an **episode** — a durable, structured record (intent, actions, findings, artifacts, open issues, handoff notes) that the orchestrator composes into further dispatches instead of re-reading raw transcripts. Slate also injects a mandatory workflow doctrine. Its design and review gates scale with the confirmed change class. Optional umbrella **draft-PR publishing** covers tracks.
8
+
9
+ An opt-in **model-failover** map adds high availability: when a model API fails, the orchestrator, worker threads, and episode compression each retry once on a configured equal-quality alternative. A second opt-in, **action-level model routing**, gives each dispatched action a model and an effort level chosen to be up to the task and no more, so cost is bounded per action instead of per session.
8
10
 
9
11
  ## Why Slate?
10
12
 
@@ -36,16 +38,29 @@ Full rationale: [`docs/design-principles.md`](docs/design-principles.md), shippe
36
38
 
37
39
  ## Feature development workflow
38
40
 
39
- In orchestrator mode, Slate injects a track-based development workflow as doctrine — it is not optional; project configuration can extend it (`doctrineExtraPath`) but never replace it. The flow:
41
+ In orchestrator mode, Slate injects a mandatory track-based development workflow. Project configuration can extend it through `doctrineExtraPath`. Configuration cannot replace it.
42
+
43
+ Slate uses four change classes. Evaluate these tests in order. The first match
44
+ sets the class:
45
+
46
+ 1. **Risky:** The change touches concurrency, durability, recovery,
47
+ transactional semantics, security, or user data. This class also covers a
48
+ public API or behavioral change, or a silent failure mode.
49
+ 2. **Complex:** The shape is unclear, several parts interact, or a live design
50
+ alternative exists.
51
+ 3. **Trivial:** The change is an obvious fix with no behavioral change, and one
52
+ reviewer pass covers it.
53
+ 4. **Medium:** Otherwise.
54
+
55
+ After classification, follow these workflow steps:
40
56
 
41
- 1. **Research** — interactive exploration; a research log opens lazily when defined triggers fire (non-trivial decisions, surprises, risky invariants, session boundaries).
42
- 2. **User design review** — the user approves the design direction before any machine review.
43
- 3. **Adversarial review** — a fresh-context reviewer attacks the design pre-implementation; findings are triaged with the user.
44
- 4. **Track split approval** — the user approves how the change splits into independently reviewable tracks.
45
- 5. **Per-track loop** — implement → agent code review → fixes → mandatory user review → marker commit (an empty commit marking the track's boundary in history).
46
- 6. **Delivery** — with draft-PR publishing enabled, the squash-merge is performed by the user; the agent never merges. With it disabled (the default), the change lands as a squashed commit that carries the workflow log's key content in its message.
57
+ 1. **Classification and research** — the orchestrator proposes the change class, and the user confirms it. A research log is required for medium changes and above.
58
+ 2. **Design gates** — medium changes need high-level design approval before implementation. Complex and risky changes add an adversarial review between two user approvals.
59
+ 3. **Track split** — the orchestrator owns the split. Size determines tracks and marker commits, not workflow gates.
60
+ 4. **Per-track loop** — each track gets implementation, fixes, and mandatory user review. Agent code review is skipped only when the whole change is trivial.
61
+ 5. **Delivery** — the user performs the squash merge when draft publishing is enabled. Otherwise, the squashed commit carries the workflow log's key content.
47
62
 
48
- The workflow scales with change size: multi-track changes get the full flow, single-track changes skip the split and the marker commits, and trivial changes shrink the pre-implementation reviews to consent plus a micro-review (skippable with explicit user consent) — the agent code review and the mandatory user review still apply at every tier. Umbrella draft-PR publishing activates only when `workflow.draftPRs` is `true`.
63
+ Trivial changes have no high-level design gate. Every change keeps mandatory user review of its track diff. Umbrella draft-PR publishing activates only when `workflow.draftPRs` is `true`.
49
64
 
50
65
  This summary is orientation only; the shipped docs listed below are normative.
51
66
 
@@ -104,6 +119,7 @@ Optional config file: `slate.json` in the project's pi config dir (`.pi/slate.js
104
119
  | `orchestratorPromptDocs` | string[] | `[]` | Project markdown files (paths relative to the project root) whose **contents** are appended to the orchestrator system prompt. |
105
120
  | `workerPromptDocs` | string[] | `[]` | Project markdown files whose **contents** are appended to every worker-thread system prompt. |
106
121
  | `workflow.draftPRs` | boolean | `false` | Enable umbrella draft-PR publishing for tracks. |
122
+ | `workflow.followUpIssues` | boolean | `false` | When true, the orchestrator asks which suggestions become follow-up issues in the project tracker. Suggestions are always reported whatever the value. |
107
123
  | `writing.check` | boolean | `false` | Add the writing doctrine rule, per-turn status, and worker guidance. An absent option is silently off. A malformed `writing` value, or a non-boolean `check` value, warns and defaults to off. Unknown `writing` keys warn and are ignored. See [`docs/writing-guidance.md`](docs/writing-guidance.md). |
108
124
  | `writing.remind` | boolean | `false` | Send a hidden reminder after an eligible tool result. All gates must pass: orchestrator mode, project trust, `writing.check`, this option, no pause, cadence or handoff force, and one-per-round control. See [`docs/writing-guidance.md`](docs/writing-guidance.md). |
109
125
  | `writing.remindPercent` | number | `10` | Set cadence as a percentage of Slate's current effective context budget. The value must be finite and in `(0, 100]`. The interval has an 8,192-token floor and no cap. A handoff force bypasses this threshold. See [`docs/writing-guidance.md`](docs/writing-guidance.md). |
@@ -124,7 +140,7 @@ Example `.pi/slate.json` (the `docs/agents/...` paths are placeholders — point
124
140
  "maxConcurrent": 4,
125
141
  "orchestratorPromptDocs": ["docs/agents/orchestrator-guidelines.md"],
126
142
  "workerPromptDocs": ["docs/agents/thread-guidelines.md"],
127
- "workflow": { "draftPRs": true },
143
+ "workflow": { "draftPRs": true, "followUpIssues": false },
128
144
  "writing": {
129
145
  "check": true,
130
146
  "remind": false,
@@ -170,7 +186,7 @@ Slate reads project configuration (`.pi/slate.json`) and injects project files (
170
186
 
171
187
  In orchestrator mode, Slate appends a short **doctrine** (a block of numbered rules) to the orchestrator's system prompt each turn. The doctrine does not embed the workflow docs — it cites them by **absolute path**, resolved inside the installed package (not your project), and the orchestrator reads them on demand. Those embedded paths are also why the block's character count depends on your install location; [`docs/context-budget.md`](docs/context-budget.md) has the measured sizes, with and without the optional rules, and the arithmetic for your own install:
172
188
 
173
- - `docs/track-workflow.md` — the track-based workflow (research → design review → adversarial review → track review)
189
+ - `docs/track-workflow.md` — the class-scaled workflow for research, high-level design, adversarial review, and track review
174
190
  - `docs/pr-publishing.md` — umbrella draft-PR publishing (cited only when `workflow.draftPRs` is `true`)
175
191
  - `docs/review-rules.md` — review discipline and finding rules
176
192
  - `docs/design-principles.md` — Slate's own design rationale
@@ -207,18 +207,18 @@ must be named instead of presented as the same measurement:
207
207
 
208
208
  | router | models | `draftPRs` | `writing.check` | paths | portable | lines |
209
209
  | --- | --- | --- | --- | --- | --- | --- |
210
- | off | — | off | off | 4 | 2,270 | 43 |
211
- | off | — | off | on | 5 | 3,340 | 65 |
212
- | off | — | on | off | 5 | 2,289 | 43 |
213
- | off | — | on | on | 6 | 3,359 | 65 |
214
- | on | `.pi/slate.json` six | off | off | 5 | 4,300 | 64 |
215
- | on | `.pi/slate.json` six | off | on | 6 | 5,370 | 86 |
216
- | on | `.pi/slate.json` six | on | off | 6 | 4,319 | 64 |
217
- | on | `.pi/slate.json` six | on | on | 7 | 5,389 | 86 |
218
- | on | all 9 shipped | off | off | 5 | 4,855 | 67 |
219
- | on | all 9 shipped | off | on | 6 | 5,925 | 89 |
220
- | on | all 9 shipped | on | off | 6 | 4,874 | 67 |
221
- | on | all 9 shipped | on | on | 7 | 5,944 | 89 |
210
+ | off | — | off | off | 4 | 2,701 | 46 |
211
+ | off | — | off | on | 5 | 3,771 | 68 |
212
+ | off | — | on | off | 5 | 2,720 | 46 |
213
+ | off | — | on | on | 6 | 3,790 | 68 |
214
+ | on | `.pi/slate.json` six | off | off | 5 | 4,731 | 67 |
215
+ | on | `.pi/slate.json` six | off | on | 6 | 5,801 | 89 |
216
+ | on | `.pi/slate.json` six | on | off | 6 | 4,750 | 67 |
217
+ | on | `.pi/slate.json` six | on | on | 7 | 5,820 | 89 |
218
+ | on | all 9 shipped | off | off | 5 | 5,286 | 70 |
219
+ | on | all 9 shipped | off | on | 6 | 6,356 | 92 |
220
+ | on | all 9 shipped | on | off | 6 | 5,305 | 70 |
221
+ | on | all 9 shipped | on | on | 7 | 6,375 | 92 |
222
222
 
223
223
  An untrusted project reads the first row whatever its `slate.json`
224
224
  says: no project config is loaded, so no optional rule renders. Line
@@ -250,8 +250,9 @@ worker extensions and support verification decisions:
250
250
 
251
251
  | basis | models | worker extensions | paths | portable | lines | rough tokens |
252
252
  | --- | ---: | --- | ---: | ---: | ---: | ---: |
253
- | current `.pi/slate.json` dogfood config | 6 | pinned-package 2 units / 4 tools | 7 | 6,305 | 96 | ≈1,576 |
254
- | stable maximal fixture | 9 | synthetic 2 units / 4 tools, every rendered field at its cap | 7 | 7,291 | 99 | ≈1,823 |
253
+ | current `.pi/slate.json` dogfood config | 6 | pinned-package 2 units / 4 tools | 7 | 6,736 | 99 | ≈1,684 |
254
+ | stable maximal fixture | 9 | synthetic 2 units / 4 tools, every rendered field at its cap | 7 | 7,722 | 102 | ≈1,931 |
255
+ | follow-up-issues maximal fixture | 9 | synthetic 2 units / 4 tools, every rendered field at its cap | 7 | 7,800 | 103 | ≈1,950 |
255
256
 
256
257
  The dogfood row uses `workflow.draftPRs: true`, `writing.check: true`, and the
257
258
  six models in `.pi/slate.json`. Its extension basis is
@@ -261,6 +262,7 @@ units and four tools. Their worker-extension rule is 916 portable characters /
261
262
  directory)`. No maintainer checkout path belongs in this shipped document.
262
263
 
263
264
  The stable maximal row uses all nine shipped profiles, draft PRs, and writing.
265
+ The follow-up-issues row uses the same basis with `workflow.followUpIssues: true`.
264
266
  Its direct post-resolution worker fixture has two units and four tools. Unit
265
267
  labels are 128 characters. Tool names are 64 characters. Descriptions are 140
266
268
  characters.
@@ -278,35 +280,46 @@ the next whole line.
278
280
 
279
281
  Two guards have different jobs. An exact pinned literal is the sensitive guard.
280
282
  It fails for every size change in its rendered fixture, including one character.
281
- The paired maximal fixtures cover rule 8 with draft pull requests enabled and
282
- disabled. The bound is a coarse ceiling that stops unbounded growth over time.
283
- A bound close to a fixture adds friction but no detection, because its exact
283
+ The maximal fixtures cover draft pull requests enabled, draft pull requests
284
+ disabled, and follow-up issues enabled. Each budget term also has one enforced
285
+ bound. The bound is a coarse ceiling that stops unbounded growth over time. A
286
+ bound close to a fixture adds friction but no detection, because its exact
284
287
  literal already detects the change. Real reserve therefore weakens nothing.
285
288
 
286
289
  A doctrine change updates the exact literal and every published measurement. A
287
290
  maintainer revisits a bound only when the reserve policy requires it. The check
288
291
  applies the five-percent rule to every upper bound, so this decision is auditable.
289
292
 
290
- | budget term | measured | old bound | current bound | current reserve |
291
- | --- | ---: | ---: | ---: | ---: |
292
- | routing rule characters | 2,585 | 4,000 | 4,000 | 1,415 |
293
- | routing rule lines | 25 | 34 | 34 | 9 |
294
- | routing fixed prose | 1,110 | 1,500 | 1,500 | 390 |
295
- | largest model row | 183 | 300 | 300 | 117 |
296
- | router-on doctrine | 4,855 | 6,500 | 6,500 | 1,645 |
297
- | writing-only doctrine | 3,340 | 5,600 | 5,600 | 2,260 |
298
- | writing plus router | 5,925 | 6,300 | 6,500 | 575 |
299
- | writing plus extensions | 3,595 | 6,000 | 6,000 | 2,405 |
300
- | writing plus router and extensions | 6,180 | 6,600 | 6,800 | 620 |
301
- | maximal doctrine, draft PRs enabled | 7,291 | 7,800 | 7,900 | 609 |
302
- | maximal doctrine, draft PRs disabled | 7,272 | 7,800 | 7,900 | 628 |
303
- | capped worker rule | 1,347 | 1,600 | 1,600 | 253 |
304
- | writing rule characters | 1,070 | 1,150 | 1,150 | 80 |
305
- | writing rule lines | 23 | 24 | 25 | 2 |
293
+ | budget term | current | enforced bound | current reserve |
294
+ | --- | ---: | ---: | ---: |
295
+ | routing rule characters | 2,585 | 4,000 | 1,415 |
296
+ | routing rule lines | 25 | 34 | 9 |
297
+ | routing fixed prose | 1,110 | 1,500 | 390 |
298
+ | largest model row | 183 | 300 | 117 |
299
+ | router-on doctrine | 5,286 | 6,500 | 1,214 |
300
+ | writing-only doctrine | 3,771 | 5,600 | 1,829 |
301
+ | writing plus router | 6,356 | 6,700 | 344 |
302
+ | writing plus extensions | 4,026 | 6,000 | 1,974 |
303
+ | writing plus router and extensions | 6,611 | 7,000 | 389 |
304
+ | maximal doctrine, draft PRs enabled | 7,722 | 8,200 | 478 |
305
+ | maximal doctrine, draft PRs disabled | 7,703 | 8,200 | 497 |
306
+ | maximal doctrine, follow-up issues enabled | 7,800 | 8,200 | 400 |
307
+ | capped worker rule | 1,347 | 1,600 | 253 |
308
+ | writing rule characters | 1,070 | 1,150 | 80 |
309
+ | writing rule lines | 23 | 25 | 2 |
310
+
311
+ The four changed bound decisions record the user's choices. The fuller
312
+ Option 3 text puts the enforcement trigger, class confirmation, presentation
313
+ order, and two previously unstated gates in the injected prompt. Writing plus
314
+ router moved from 6,500 to 6,700. Writing plus router and extensions moved from
315
+ 6,800 to 6,900. The maximal family moved from 7,900 to 8,200. Writing plus router
316
+ and extensions then moved from 6,900 to 7,000 with user approval so rule 8 could
317
+ keep the skip-the-read clause that rules 9 and 10 also carry. A redundant read of
318
+ the track workflow document costs far more than the clause.
306
319
 
307
320
  The positive control adds one capped tool and four copies of the largest
308
- measured model row. It measures 8,239 portable characters and exceeds the new
309
- 7,900-character maximal bound by 339. That margin remains larger than the
321
+ measured model row. It measures 8,670 portable characters and exceeds the
322
+ 8,200-character maximal bound by 470. That margin remains larger than the
310
323
  184-character maximum model-row growth and the 212-character capped tool growth.
311
324
  The raised bound does not blunt the positive control.
312
325
 
@@ -314,11 +327,12 @@ These figures are verification budgets, never runtime limits. Arbitrary user
314
327
  extension rosters can exceed them. Keep the positive-control steps unchanged
315
328
  unless the fixture design itself changes.
316
329
 
317
- Against a 256,000-token context budget, these blocks remain small. At four
318
- characters per token as a rough estimate, the shipped-rule table ranges from
319
- about 568 tokens to about 1,486 tokens. The current dogfood basis is about 1,576
320
- tokens. The representative maximum is about 1,823 tokens, or 0.72 percent of the
321
- default budget.
330
+ Against a 256,000-token context budget, these blocks remain small. The rough
331
+ estimate divides each measured portable-character render by four and rounds to
332
+ the nearest whole token. The shipped-rule table ranges from about 675 tokens to
333
+ about 1,594 tokens. The current dogfood basis is about 1,684 tokens. The stable
334
+ representative maximum is about 1,931 tokens. The follow-up-issues maximum is
335
+ about 1,950 tokens, or 0.76 percent of the default budget.
322
336
 
323
337
  No tokenizer was run, and tables are denser than prose. The block is re-sent on every request rather than paid once. These figures show how
324
338
  much headroom Slate consumes before conversation content.
@@ -312,19 +312,19 @@ the load-on-demand discipline the extension itself prescribes:
312
312
 
313
313
  - **Tier 1 — always loaded.** The doctrine in `mode.ts` is the operational
314
314
  distillation of P1–P10, the review discipline defined in
315
- `review-rules.md`, and a pointer to the track-based workflow protocol
316
- that ships with this package (`track-workflow.md` in this directory),
315
+ `review-rules.md`, and a pointer to the class-scaled track workflow
316
+ protocol that ships with this package (`track-workflow.md` in this directory),
317
317
  appended to the system prompt every turn while orchestrator mode is
318
318
  on. Sizing it matters to the tiering argument, so it is measured
319
319
  rather than asserted: with every conditional tail rule off and
320
- `workflow.draftPRs` off, the block is **2,270 portable characters /
321
- 43 lines**, and configuring the router for six models nearly
322
- doubles it, to **4,300** on that same basis — the routing rule
320
+ `workflow.draftPRs` off, the block is **2,701 portable characters /
321
+ 46 lines**, and configuring the router for six models nearly
322
+ doubles it, to **4,731** on that same basis — the routing rule
323
323
  renders one table row per routable model. (Portable characters, and
324
324
  the rest of the configurations, are defined and tabulated in
325
325
  `context-budget.md`; the raw count also depends on where the package
326
326
  is installed, because the doctrine embeds absolute doc paths.) At a
327
- rough 4 characters per token that is order-500 tokens, order-1,000
327
+ rough 4 characters per token that is order-700 tokens, order-1,200
328
328
  with the router on — so the original "a few hundred tokens" holds
329
329
  only for the fixed rules, and a configured router buys its table with
330
330
  a real slice of every request. It still covers everything routine
@@ -507,7 +507,7 @@ model's ladder is unreadable.
507
507
  all nine. In the current snapshot a model row costs 146–183
508
508
  characters, plus a one-off legend clause for each marker it
509
509
  introduces. Configuring the router roughly doubles Slate's
510
- always-loaded block (2,270 characters with routing and writing
510
+ always-loaded block (2,701 characters with routing and writing
511
511
  off). Those are PORTABLE characters — the
512
512
  doctrine with each occurrence of the installed `docs/` directory
513
513
  removed, filenames kept — because the doctrine embeds absolute doc
@@ -9,21 +9,36 @@ workflow-log lifecycle in that mode is owned by track-workflow.md
9
9
 
10
10
  ## Creation
11
11
 
12
- The umbrella draft PR is created once the design has passed the user
13
- design review and the adversarial review, BEFORE implementation:
12
+ For every change with a high-level design, draft the PR description
13
+ before the pre-implementation presentation. Present the draft alongside
14
+ the high-level design, so one approval covers both. The description has
15
+ no separate approval gate.
16
+
17
+ The umbrella draft PR is created after the gate required by the
18
+ confirmed change class passes and BEFORE implementation. For a complex
19
+ or risky change, that gate is the final high-level design approval after
20
+ the adversarial review. For a medium change, it is the high-level design
21
+ approval. A trivial change has no high-level design gate, so the PR is
22
+ created after the user confirms the class and before implementation:
14
23
 
15
24
  - Created as a DRAFT, based on the repository's default development
16
25
  branch.
17
26
  - If the working branch has no diff against the base yet, land a
18
27
  bootstrap empty commit so the PR can be created.
19
- - At creation, the research log's content folds into the PR
20
- description — Key decisions, Risks, and Open questions feed the
21
- corresponding Planned-changes subsections, and the design review and
22
- adversarial review verdict lines land in Risks & accepted
23
- trade-offs — and the log file is deleted. Decisions made after PR
24
- creation are appended to the PR description directly.
25
- - The user approves the description (and the track split — see
26
- track-workflow.md) before implementation starts.
28
+ - At creation for a medium, complex, or risky change, the research
29
+ log's Planned changes content folds into the PR description. Key
30
+ decisions, Risks, and Open questions feed the corresponding
31
+ Planned-changes subsections. The applicable design review verdict
32
+ lines land in Risks & accepted trade-offs. The adversarial review
33
+ verdict line lands there only when that review ran; a medium change
34
+ carries the design verdict lines alone.
35
+ - For a trivial change, the initial request supplies Motivation. The
36
+ confirmed class proposal and intended fix supply Planned changes. If
37
+ a log exists, its relevant decisions and Open Questions also fold
38
+ into the description.
39
+ - The research log is retained until delivery, and its Decision Log
40
+ keeps appending during implementation. track-workflow.md § Research
41
+ log owns the full lifecycle.
27
42
 
28
43
  ## Description rules
29
44
 
@@ -46,8 +61,13 @@ Subsections activate when their content exists:
46
61
  - **Key decisions** — chosen vs rejected; preempts "why not X?" review
47
62
  comments.
48
63
  - **Out of scope** — explicit non-goals.
49
- - **Risks & accepted trade-offs** — including the design review and
50
- adversarial review verdict lines.
64
+ - **Risks & accepted trade-offs** — including the applicable design
65
+ review verdict lines, and the adversarial review verdict line only
66
+ when that review ran.
67
+ - **Suggestions** — a one-line index per suggestion: identifier,
68
+ location, and one-line summary. The standalone text lives in the
69
+ final report to the user or in a tracker issue when
70
+ `workflow.followUpIssues` enables that prompt.
51
71
  - **Verification approach** — 1–2 lines.
52
72
 
53
73
  "Deep enough" test: a reviewer who knows the codebase but not this
@@ -113,7 +133,10 @@ executed in order:
113
133
  review) is completed or explicitly user-waived — flipping never
114
134
  discards a pending review.
115
135
  - All commits landed since the last user-approved gate are presented
116
- to the user.
136
+ to the user. For a trivial change, present the description here
137
+ because no design gate presented it before implementation.
138
+ - Every remaining suggestion is reported to the user, and the
139
+ Suggestions index is present in the description.
117
140
  - Strip the whole Tracks section from the description, whatever its
118
141
  form — the table for multi-track changes or the "N/A (single-track)"
119
142
  placeholder — plus any notes under it. Track numbers are ephemeral
@@ -153,6 +176,9 @@ of any recorded size exception.
153
176
 
154
177
  ## After the merge
155
178
 
179
+ Complete the research-log delivery cleanup defined by
180
+ track-workflow.md § Research log.
181
+
156
182
  Any cleanup a layered peer-review process requires (closing its review
157
183
  PRs, deleting its pinned branches) is an agent duty, executed when the
158
184
  user reports the merge or a later session detects it, per that
@@ -15,8 +15,11 @@ type, also embed the §7 obligations or direct the reviewer to read them.
15
15
 
16
16
  ## 1. When to review
17
17
 
18
- - Every non-trivial change gets reviewed before it is declared done.
19
- - Rigor scales with risk of the change, never with effort already spent.
18
+ - The agent code review of a track is skipped only when the whole change
19
+ is trivial. No track inside a medium, complex, or risky change is
20
+ trivial. Every required review occurs before the change is declared
21
+ done. [track-workflow.md](track-workflow.md) defines these classes.
22
+ - Rigor scales with the change class, never with effort already spent.
20
23
  When in doubt, review more.
21
24
  - For long multi-step work streams, review high-risk steps in isolation
22
25
  right after they land — defects localized to one step get buried once
@@ -32,9 +35,18 @@ type, also embed the §7 obligations or direct the reviewer to read them.
32
35
  dispatch. Use `adversarial` for a perspective that actively seeks
33
36
  counterexamples and `reviewer` for every other review perspective.
34
37
  - Do not pass implementer episodes or implementer reasoning to
35
- reviewers. Give a reviewer the artifact/diff, the intent of the
36
- change, its in-scope files, and its charter plus reasoning/output
37
- obligations (see the intro).
38
+ reviewers. Section 8 defines the single exception.
39
+ - Every review dispatch includes the artifact/diff, the charter plus
40
+ reasoning/output obligations (see the intro), and a TRACK INTENTION
41
+ BLOCK with these four fields:
42
+ - target;
43
+ - scope boundary;
44
+ - deferred work;
45
+ - acceptance condition.
46
+ When no track exists, such as during a design-stage adversarial
47
+ review, the same four fields describe the whole change instead.
48
+ A reviewer without a target grades against an ideal and inflates
49
+ severity.
38
50
  - Independent perspectives run in PARALLEL on the same artifact.
39
51
 
40
52
  ## 3. Choose perspectives by what the change touches
@@ -143,13 +155,44 @@ perspective's charter:
143
155
  free number for its prefix.
144
156
  - Severity: **blocker** (must fix before done), **should-fix** (fix
145
157
  unless explicitly justified and reported), **suggestion** (optional).
146
- - Synthesize across reviewers: deduplicate by location/root cause,
147
- keep all contributing IDs on the merged finding, and take the
148
- highest severity when duplicates disagree (upgrade-only — never
149
- downgrade a severity during synthesis).
158
+ - Grade severity against the stated target of the track. A defect that
159
+ stops the track from reaching its target is a blocker or should-fix.
160
+ A defect outside the target is a suggestion.
161
+ - Target-relative grading never lowers a safety defect or a correctness
162
+ defect. This safety floor protects concurrency, durability, recovery,
163
+ transactional semantics, a public API or behavioral change, security,
164
+ user data, and a missing test for a changed branch. Target-relative
165
+ grading can lower style concerns, refactoring opportunities,
166
+ neighboring-code concerns, and structural preferences.
167
+ - Synthesize across reviewers by deduplicating findings with the same
168
+ location or root cause. Keep all contributing IDs on the merged
169
+ finding, and take the highest reviewer severity when duplicates
170
+ disagree. This upgrade-only rule governs deduplication only.
171
+ - After synthesis, the orchestrator validates every finding's severity,
172
+ because the orchestrator holds the widest view of the change. It may
173
+ raise or lower a severity. It may not lower a finding that a gate
174
+ thread marked STILL OPEN or REGRESSION. Lowering a blocker requires
175
+ user confirmation.
176
+ - Every change records the reviewer severity, validated severity,
177
+ validation reason, reviewer episode identifier, and observation path
178
+ for every finding. The final report shows the reviewer and validated
179
+ severities side by side.
180
+ - Blockers and should-fix findings are fixed inside the change. Every
181
+ other finding becomes a suggestion and follows §5.
150
182
 
151
183
  ## 5. Reviewers find, implementers fix
152
184
 
185
+ - An implementation-stage suggestion is NEVER fixed inside the change
186
+ that found it. Design-stage triage follows track-workflow.md § Finding
187
+ triage instead. The orchestrator collects implementation-stage
188
+ suggestions and presents them at the end. Each entry states what,
189
+ where, why it matters, and what a fix needs. The entry must be
190
+ readable without the review that produced it. The delivery record
191
+ preserves a durable one-line index of every suggestion. The
192
+ standalone text lives in the final report to the user or in a tracker
193
+ issue. `workflow.followUpIssues` controls only whether the
194
+ orchestrator asks which suggestions become tracker issues. The key
195
+ defaults to `false`. An off value never discards a suggestion.
153
196
  - Review threads never edit files; fix work is dispatched to an
154
197
  implementation thread (usually the one that produced the change, or
155
198
  a fresh one if it is gone or compromised — context-poisoned or
@@ -197,6 +240,8 @@ perspective's charter:
197
240
 
198
241
  ## 6. Iteration and termination
199
242
 
243
+ - The review loop is internal to the orchestrator. Do not show the user
244
+ each iteration.
200
245
  - After fixes, re-verify each addressed finding — in a gate thread,
201
246
  not by trusting the fixer's claim. Dispatch every gate thread with the
202
247
  `reviewer` type. A gate thread is a fresh thread whose sole job is
@@ -212,11 +257,16 @@ perspective's charter:
212
257
  - **REGRESSION** — the fix broke something else; file the breakage
213
258
  as a new blocker (RG prefix).
214
259
  - Blockers loop until clear. Should-fix findings get up to 3
215
- iterations for normal changes; go deeper only for high-risk changes.
216
- - No-progress rule: if an iteration clears nothing and surfaces no new
217
- fixable finding, stop and escalate to the user instead of spinning.
218
- - Done = no blockers remain, addressed findings VERIFIED, and any
219
- remaining should-fix/suggestions explicitly reported to the user.
260
+ iterations. The escape hatch in §8 is available when a trigger fires.
261
+ - These escalations always reach the user: an iteration that clears
262
+ nothing, a third iteration on should-fix findings, a second regression
263
+ filed on one finding, and any proposed lowering of a blocker.
264
+ - No-progress rule: if an iteration clears nothing, stop the ordinary
265
+ fix loop and escalate to the user instead of spinning. The escape
266
+ hatch in §8 remains available.
267
+ - Done = no blockers remain, every addressed finding is VERIFIED, no
268
+ should-fix remains open without a recorded justification, and every
269
+ suggestion is reported to the user.
220
270
 
221
271
  ## 7. Reviewer evidence standards (how reviewers argue)
222
272
 
@@ -264,3 +314,23 @@ than implement its method.
264
314
  arguments carry no formal guarantee and do not replace running the
265
315
  project's checks.
266
316
  <!-- reviewer-charter:end -->
317
+
318
+ ## 8. Escape-hatch adversarial review
319
+
320
+ - The escape hatch is available when a fix iteration clears nothing, a
321
+ gate thread returns STILL OPEN twice on one finding, the implementer
322
+ cannot locate the cause, or a fix keeps producing regressions.
323
+ - The hatch dispatches a fresh adversarial thread. Its job is to explain
324
+ why the fix fails, not to grade the change.
325
+ - This review is separate from the pre-implementation adversarial review
326
+ in [track-workflow.md](track-workflow.md). Neither review satisfies the
327
+ other. The escape hatch is available at every change class.
328
+ - This review is the single exception to the §2 ban on passing
329
+ implementer episodes to reviewers. The orchestrator passes the
330
+ smallest episode subset that carries the evidence. It names every
331
+ episode passed and states why each one is needed.
332
+ - The hatch output is evidence, not a verdict. It closes no finding and
333
+ lowers no severity. A null verdict proves nothing. Anything the hatch
334
+ raises goes to a normal gate thread for a verdict.
335
+ - The hatch needs no research log. Append any decision that comes out of
336
+ it to the Decision Log.
@@ -93,6 +93,10 @@ The orchestrator chooses the work stream, thread, model, effort, task, and requi
93
93
 
94
94
  The tool makes one narrow economic judgement. It decides whether continuing the named thread costs more than a fresh thread seeded with named episodes.
95
95
 
96
+ A blanket refusal of a thread restart has a price. Refuse a restart only when the next action depends on context from the previous action that the thread's episodes do not carry. The orchestrator can apply this test because it reads those episodes before choosing the successor's context.
97
+
98
+ The compressed path is instructed to retain published findings, approved decisions, named file paths, recorded verification results, commands, error messages, and outcomes. The fallback path carries the task and up to 8,000 characters of the raw final worker output instead. Therefore the first group is available on the compressed path when retained, and on the fallback path only when the final output contains it. Terminal output can reach a fallback episode when the worker pasted it into that output. Compression can also retain terminal details when they are relevant, so terminal output is not a universal exclusion. Unrecorded intermediate reasoning and conversational details omitted from the final output remain unavailable on the fallback path, while compression is instructed to drop tactical noise. Continue the live thread when the next action needs context the episode does not contain. Permit a restart when the episode contains the context needed to act.
99
+
96
100
  ### Permission through `freshContext`
97
101
 
98
102
  The `freshContext` contract asks three separate questions:
@@ -2,51 +2,107 @@
2
2
 
3
3
  The mandatory flow for every change delivered under this workflow:
4
4
 
5
- Research → (lazy) research log → user design review → adversarial
6
- review → user approves the track split → per-track loop (implement →
7
- track code review → fixes → mandatory user review → marker commit) →
8
- delivery.
5
+ Research → confirm the change class → open a research log when required
6
+ → prepare the high-level design for medium, complex, and risky changes
7
+ → obtain pre-adversarial approval and adversarial review for complex and
8
+ risky changes → obtain pre-implementation approval for every high-level
9
+ design → per-track loop (implement → track code review when required →
10
+ fixes → mandatory user review → marker commit when required) → delivery.
9
11
 
10
12
  Publishing is conditional on `workflow.draftPRs` in the project's
11
13
  `slate.json` (default: false). When it is ENABLED, an umbrella draft
12
- PR is created after both reviews pass and before implementation
13
- starts — see pr-publishing.md in this directory for all PR mechanics.
14
- When it is DISABLED, the workflow log is the change's durable record;
15
- its lifecycle is defined in § Research log below. Marker commits work
16
- identically in both modes.
17
-
18
- The flow scales with change size:
19
-
20
- | Change size | What applies |
21
- | --- | --- |
22
- | Multi-track change | Full flow as described above. |
23
- | Single-track change | No track split, no marker commits. Everything else applies. |
24
- | Trivial change (typo, doc-only, mechanical rename, obvious one-file fix) | No split. The planned-changes statement is a 2–3-sentence paragraph; the design review collapses into user consent to it. Micro adversarial review, or skip it with explicit user consent. |
25
-
26
- The mandatory user review gate applies at EVERY tier. For single-track
27
- and trivial changes the whole branch diff is the track, so the user
28
- review sits after the agent code review and before delivery.
29
-
30
- Throughout this document, the "planned-changes statement" is the
31
- high-level design summary of the change. With publishing enabled it
32
- becomes the Planned-changes section of the PR description (see
33
- pr-publishing.md); with publishing disabled it lives in the workflow
34
- log.
14
+ PR is created after the applicable pre-implementation gates pass and
15
+ before implementation starts — see pr-publishing.md in this directory
16
+ for all PR mechanics. When it is DISABLED, the workflow log is the
17
+ change's durable record; its lifecycle is defined in § Research log
18
+ below. Marker commits work identically in both modes.
19
+
20
+ ## Change classes
21
+
22
+ Gates key on the change class, not on size. Evaluate these tests in order.
23
+ The first match sets the class:
24
+
25
+ 1. **Risky:** The change touches concurrency, durability, recovery,
26
+ transactional semantics, security, or user data. This class also covers a
27
+ public API or behavioral change, or a silent failure mode.
28
+ 2. **Complex:** The shape is unclear, several parts interact, or a live design
29
+ alternative exists.
30
+ 3. **Trivial:** The change is an obvious fix with no behavioral change, and one
31
+ reviewer pass covers it.
32
+ 4. **Medium:** Otherwise.
33
+
34
+ The orchestrator proposes the class and the user confirms it. The
35
+ proposal states the class, the reason, and the property that would
36
+ raise it. The orchestrator re-proposes the class whenever new
37
+ information appears. An upgrade to any higher class after implementation
38
+ starts pauses implementation. The orchestrator opens and backfills a
39
+ research log when the new class requires one, then runs every newly
40
+ required gate over the WHOLE change before implementation resumes. A
41
+ gate whose prescribed timing has passed runs retroactively. The class
42
+ is never lowered after implementation starts.
43
+
44
+ Size drives only the track split and marker commits. The orchestrator
45
+ owns the track split at every class; it is not a user approval gate.
46
+
47
+ ### Worked classification examples
48
+
49
+ **Trivial — correct one misspelled word in an internal comment.**
50
+
51
+ - Step 1 does not match because no risky category changes.
52
+ - Step 2 does not match because the shape is clear and no parts interact.
53
+ - Step 3 matches. The correction is an obvious fix, behavior does not change,
54
+ and one reviewer pass can verify the complete diff.
55
+ - Result: **Trivial**.
56
+
57
+ **Medium — rename one internal helper and update its 40 call sites.**
58
+
59
+ - Step 1 does not match because no public surface, behavior, or other risky
60
+ category changes.
61
+ - Step 2 does not match because the mechanical shape is clear, the call sites
62
+ do not interact, and no design alternative exists.
63
+ - Step 3 does not match. The repository-wide refactor is not an obvious fix,
64
+ and one reviewer pass cannot cover all references, strings, and documentation.
65
+ - Step 4 matches by default.
66
+ - Result: **Medium**.
67
+
68
+ **Complex — reorganize test-fixture assembly across its loader, builder, and
69
+ cleanup modules.**
70
+
71
+ - Step 1 does not match because production behavior and every risky category
72
+ stay unchanged.
73
+ - Step 2 matches. Several parts interact, and live alternatives either
74
+ centralize fixture state or pass it explicitly between the modules.
75
+ - Result: **Complex**.
76
+
77
+ ### Gate matrix
78
+
79
+ | Gate | Trivial | Medium | Complex | Risky |
80
+ | --- | --- | --- | --- | --- |
81
+ | High-level design | No | Yes | Yes | Yes |
82
+ | High-level design shown before adversarial review | No | No | Yes | Yes |
83
+ | High-level design shown before implementation | No | Yes | Yes | Yes |
84
+ | Adversarial review of the high-level design | No | No | Yes | Yes |
85
+ | Research log | No, unless a trigger fires | Yes | Yes | Yes |
86
+ | Agent code review of a track | No, when the whole change is wholly trivial | Yes | Yes | Yes |
87
+ | User review of the track diff | Yes | Yes | Yes | Yes |
88
+
89
+ The track split belongs to the orchestrator at every class.
35
90
 
36
91
  ## Research phase (lightweight)
37
92
 
38
93
  Research is interactive exploration before any implementation: read
39
94
  real source code, trace call chains, and clarify aims and constraints
40
- with the user. There is no design document, no implementation plan,
41
- and no mandatory artifacts. The phase ends when the initial design of
42
- the change is understood and has passed the user design review (see
43
- below).
95
+ with the user. Before the class is settled, no design document,
96
+ implementation plan, or mandatory artifact is assumed. The phase ends
97
+ when the initial shape and class of the change are understood.
44
98
 
45
- ## Research log (lazy-triggered)
99
+ ## Research log
46
100
 
47
- Start research WITHOUT a log. Open one the moment any trigger below
48
- fires, then backfill the decisions already made — backfilling is cheap
49
- while they are still in context.
101
+ A research log is mandatory for every change above trivial. For the
102
+ trivial class, and during research before the class is settled, start
103
+ research WITHOUT a log. Open one the moment any trigger below fires,
104
+ then backfill the decisions already made — backfilling is cheap while
105
+ they are still in context.
50
106
 
51
107
  | # | Trigger |
52
108
  | --- | --- |
@@ -57,9 +113,19 @@ while they are still in context.
57
113
  | 5 | The change is multi-track. |
58
114
  | 6 | The user requests it. |
59
115
 
116
+ The trigger table governs the trivial class and research before class
117
+ confirmation. Once the user confirms a class above trivial, the log is
118
+ mandatory whether or not a trigger fired.
119
+
120
+ The Decision Log remains append-only throughout research and
121
+ implementation. It records decisions taken after implementation
122
+ starts because the log is the record that survives a context handoff.
123
+ At high-level design approval, it records the workflow rule-set version and the
124
+ gates already passed.
125
+
60
126
  ### Log format
61
127
 
62
- Four sections, opened with the log:
128
+ Four sections are opened with the log:
63
129
 
64
130
  - **Initial request** — verbatim, written once.
65
131
  - **Decision Log** — append-only. Each entry is at most 4 lines: the
@@ -69,44 +135,53 @@ Four sections, opened with the log:
69
135
  - **Surprises & Discoveries**
70
136
  - **Open Questions**
71
137
 
72
- Two more named sections join as the corresponding phase begins:
138
+ Three more named sections join as the corresponding material appears:
73
139
 
74
- - **Planned changes** — the planned-changes statement, added when the
75
- design converges; the design review and adversarial review verdict
76
- lines are appended at its end. (With publishing enabled this section
77
- feeds the PR description at umbrella-PR creation.)
78
- - **Track table** — publishing disabled only: added when the user
79
- approves the track split (constraints in § Track table). With
80
- publishing enabled the table lives in the PR description from
81
- creation instead.
140
+ - **Planned changes** — contains the high-level design when it
141
+ converges; the applicable design-review and adversarial-review
142
+ verdict lines are appended at its end.
143
+ - **Suggestions** — one standalone entry per suggestion. Each entry
144
+ states what the suggestion is, where it applies, why it matters,
145
+ and what a fix needs. It MUST be readable without the review that
146
+ produced it.
147
+ - **Track table** — added when the orchestrator splits the change into
148
+ tracks (constraints in § Track table). With publishing enabled the
149
+ table also lives in the PR description as pr-publishing.md directs.
82
150
 
83
151
  ### Persistence
84
152
 
85
- During research the log lives as an untracked file `research-log.md`
86
- at the repo root. What happens next depends on `workflow.draftPRs`:
87
-
88
- - **Enabled** — the log's life ends at umbrella-PR creation: its
89
- content folds into the PR description and the file is deleted
90
- (mechanics owned by pr-publishing.md § Creation).
91
- - **Disabled (default)** — the log is RETAINED at the repo root as the
92
- change's workflow log until the change is delivered (§ Delivery
93
- below). The planned-changes statement and both verdict lines anchor
94
- in its Planned changes section, the track table in its Track table
95
- section (§ Log format), and post-design decisions keep appending to
96
- the Decision Log.
153
+ During the change the log lives as an untracked file
154
+ `research-log.md` at the repo root. The log is RETAINED until delivery
155
+ with `workflow.draftPRs` either enabled or disabled. Post-design and
156
+ implementation decisions keep appending to its Decision Log.
157
+ pr-publishing.md owns how the log content reaches the pull request
158
+ description when publishing is enabled.
97
159
 
98
- ### Delivery (publishing disabled)
160
+ ### Delivery
99
161
 
100
162
  A change is DELIVERED when its final squashed commit lands on the
101
163
  repository's default development branch, or when the user explicitly
102
- abandons it. At delivery the agent folds the log into the delivery
103
- commit's message body — the motivation, the planned-changes statement,
104
- and both verdict lines: the same content that would have become the PR
105
- description — strips the track table (track numbers are ephemeral
106
- branch-life identifiers and would dangle in history), resolves or
107
- explicitly hands any remaining Open Questions to the user, then
108
- deletes the log file. On abandonment the agent deletes the log file
109
- after offering its content to the user for archiving.
164
+ abandons it. With publishing disabled for a medium, complex, or risky
165
+ change, the agent folds the log into the delivery commit's message body
166
+ — the motivation, Planned changes, and the applicable verdict lines:
167
+ the same content that would have become the PR description — and strips
168
+ the track table (track numbers are ephemeral branch-life identifiers and
169
+ would dangle in history). For a trivial change, the initial request
170
+ supplies the motivation, and the confirmed class proposal plus
171
+ implemented result supply Planned changes. If that trivial change has a
172
+ log, also fold in its relevant decisions and Open Questions. In either
173
+ case, resolve or explicitly hand any remaining Open Questions to the
174
+ user, then delete any log file. With publishing enabled,
175
+ pr-publishing.md owns delivery of the log content. When the user reports
176
+ the merge or a later session detects it, the agent deletes the retained
177
+ local log. In both modes the retained local log is deleted only at
178
+ delivery. On abandonment the agent deletes the log file after offering
179
+ its content to the user for archiving.
180
+
181
+ The delivery commit body carries a one-line index of every suggestion:
182
+ identifier, location, and one-line summary. The standalone suggestion
183
+ text lives in the final report to the user, or in a tracker issue when
184
+ the project enables that prompt.
110
185
 
111
186
  Aim to keep the final delivery commit body at or below 16,384 UTF-8
112
187
  bytes, excluding the subject. This is a target, not a gate. Measure
@@ -139,103 +214,88 @@ nor an exercised exception for publishing-disabled delivery.
139
214
 
140
215
  ### Under-trigger guardrail
141
216
 
142
- When shaping the planned-changes statement without a log, state this
143
- explicitly (e.g. "no log kept — one trivial decision, no surprises")
144
- so the user can override and request one.
217
+ For a trivial change shaped without a log, state this explicitly (for
218
+ example, "no log kept — one trivial decision, no surprises") so the
219
+ user can override and request one. This guardrail applies only to the
220
+ trivial class.
221
+
222
+ ## High-level design and user review
145
223
 
146
- ## User design review (mandatory, pre-adversarial)
224
+ The **high-level design** is the workflow's single design artifact. It
225
+ is required for medium, complex, and risky changes. It contains only the
226
+ goal, approach, key decisions, rejected alternatives, risks, scope
227
+ boundary, and open questions. Implementation detail belongs to code
228
+ review, not to the high-level design.
147
229
 
148
- When research converges, the agent presents the design to the user:
149
- the proposed approach, key decisions with the alternatives rejected,
150
- risks, and open questions. The presentation input is keyed on log
151
- existence, the same way as the adversarial review's: log exists →
152
- present from the log; no log → present the draft planned-changes
153
- statement. The agent then loops on user feedback — revising the design
154
- (and log) — until the user explicitly approves. Only after that
155
- approval does the adversarial review run.
230
+ For complex and risky changes, present the high-level design twice: once
231
+ before the adversarial review, and once before implementation. For
232
+ medium changes, present it once before implementation. For trivial
233
+ changes, there is no high-level design and no consent gate. When the
234
+ project sets `writing.check` to true, the high-level design follows the
235
+ project's writing convention.
156
236
 
157
- Rationale: the user owns the design direction. Reviewing with the user
158
- first means the adversarial review attacks a stabilized, user-endorsed
159
- design instead of one the user may still redirect — adversarial rounds
160
- are not spent on designs that would change anyway. The loop mechanics
161
- mirror the track loop's mandatory user review (present → feedback →
162
- explicit approval); the position relative to machine review is
163
- deliberately inverted — here the user reviews first.
237
+ At each presentation, the orchestrator loops on user feedback and
238
+ revises the high-level design and log until the user explicitly
239
+ approves. For a complex or risky change, append this verdict line after
240
+ the first approval:
241
+
242
+ ```
243
+ Design review (pre-adversarial): user-approved — YYYY-MM-DD
244
+ ```
164
245
 
165
- Durable record — append a verdict line to the log:
246
+ For every change with a high-level design, append this second verdict
247
+ line after the approval immediately before implementation:
166
248
 
167
249
  ```
168
- Design review: user-approved — YYYY-MM-DD
250
+ Design review (pre-implementation): user-approved — YYYY-MM-DD
169
251
  ```
170
252
 
171
- With no log, append the line to the draft planned-changes statement
172
- instead. With publishing enabled it travels into the PR description at
173
- umbrella-PR creation (pr-publishing.md § Creation); with publishing
174
- disabled the workflow log's Planned changes section is the verdict
175
- line's only durable home — writing the first verdict line opens the
176
- log if none exists, seeded with the planned-changes statement. (Crossing a session boundary before the change is published
177
- or delivered is research-log trigger #4.) The verdict line is written
178
- at every tier; at the trivial tier it is appended after the
179
- planned-changes paragraph, which stands in for the Risks & accepted
180
- trade-offs subsection.
181
-
182
- Tier scaling: at the trivial tier the design review collapses into the
183
- user's consent to the 2–3-sentence planned-changes paragraph. With
184
- publishing enabled, the ask for trivial and single-track changes may
185
- be batched: the agent presents the design together with the draft PR
186
- description in ONE pre-adversarial ask, and the user's single approval
187
- covers both. Umbrella-PR creation still follows the adversarial
188
- review; the description is re-presented only if adversarial triage
189
- changed it.
190
-
191
- ## Adversarial review (mandatory, pre-implementation)
192
-
193
- Adversarial review runs after the user approves the design in the user
194
- design review, BEFORE the planned-changes statement is finalized and
195
- implementation starts, for EVERY change. The rationale, briefly:
196
- critique activates latent knowledge that constructive planning does
197
- not (generator/critic asymmetry), and a fresh-context reviewer has no
198
- anchoring on the author's rationale.
199
-
200
- The reviewer must be a fresh context (sub-agent or fresh session) that
201
- did not author the decisions.
202
-
203
- Input is keyed on log existence:
204
-
205
- - Log exists → the adversary attacks the log (plus its cited
206
- evidence).
207
- - No log → the adversary attacks the draft planned-changes statement.
208
- - Trivial tier → micro-review with one bounded question ("what breaks
209
- / what am I not seeing?"), or skipped with explicit user consent.
210
-
211
- Charter scaling: for single-track changes, limit the mandate to
212
- correctness, hidden coupling, and missed alternatives — style and
213
- speculative scope creep are out of bounds.
214
-
215
- Licensed null verdict: "no substantive findings" is an acceptable,
216
- respected outcome — the review prompt must say so.
217
-
218
- Triage each finding with the user. Three outcomes:
253
+ The Planned changes section of the retained log is the durable home
254
+ for the high-level design and both lines. If adversarial triage changes
255
+ the high-level design, the second presentation shows every change
256
+ before the user gives the pre-implementation approval.
257
+
258
+ ## Adversarial review of the high-level design
259
+
260
+ Adversarial review runs only for complex and risky changes. It runs
261
+ after the user approves the high-level design for review and before its
262
+ pre-implementation presentation. The reviewer judges the HIGH-LEVEL DESIGN.
263
+ Implementation detail and style are out of bounds. The reviewer must
264
+ be a fresh context that did not author the decisions.
265
+
266
+ The adversary attacks the log and its cited evidence. Licensed null
267
+ verdict: "no substantive findings" is an acceptable, respected outcome
268
+ — the review prompt MUST say so.
269
+
270
+ ### Finding triage
271
+
272
+ The orchestrator triages every finding itself with one of three
273
+ outcomes:
219
274
 
220
275
  - **Strengthen** — enrich the alternatives-rejected rationale of the
221
276
  attacked decision.
222
277
  - **Reverse** — change the decision now, while it is still cheap.
223
278
  - **Accept-as-risk** — record it in Open Questions / Risks.
224
279
 
225
- Triage runs with the user, so a Reverse outcome is itself
226
- user-endorsed; after any reversal, refresh the design-review verdict
227
- line (new date) before any further adversarial round (a round-2
228
- reversal refreshes the line before the change is declared reviewed).
280
+ Every reversal and every accepted risk appears in the high-level design
281
+ that the user approves before implementation. A design-stage finding is
282
+ triaged at design time whatever its severity. review-rules.md §5 governs
283
+ implementation-stage suggestions, not design-stage findings.
229
284
 
230
- One round by default; run a second round only if any decision was
231
- actually reversed. Append a verdict line to the log (or to the draft
232
- planned-changes statement if there is no log — same homing rules as
233
- the design-review verdict line):
285
+ One round runs by default. A second round runs only after a reversal.
286
+ Append a verdict line to the log:
234
287
 
235
288
  ```
236
289
  Adversarial review: passed, N accepted risks — YYYY-MM-DD
237
290
  ```
238
291
 
292
+ ### Escape hatch during implementation
293
+
294
+ review-rules.md in this directory defines a separate escape-hatch
295
+ adversarial review. It runs during implementation when a fix is stuck.
296
+ It is separate from this pre-implementation gate. Its output is
297
+ evidence and never a verdict.
298
+
239
299
  ## Track loop
240
300
 
241
301
  A track is one unit in a stacked series: it builds on the tracks
@@ -243,10 +303,12 @@ before it, stands alone as an independently reviewable diff, and
243
303
  carries as much of the change as one reviewable diff holds.
244
304
 
245
305
  Sizing (soft bounds): a track of ≤~12 in-scope files folds into a
246
- neighbor; >~20–25 in-scope files is a split candidate.
306
+ neighbor; >~20–25 in-scope files is a split candidate. Size determines
307
+ the split and whether marker commits are needed. It does not determine
308
+ the change class or any gate.
247
309
 
248
- The user approves the proposed track split before implementation
249
- starts. Mid-flight changes to the split are re-presented to the user.
310
+ The orchestrator owns the track split. No user approval gate applies
311
+ to the split.
250
312
 
251
313
  All development is linear on the single working branch; each track is
252
314
  a contiguous commit range. Track numbering is append-only: completed
@@ -254,24 +316,38 @@ tracks never renumber, a replanned remainder gets new numbers, and
254
316
  abandoned planned tracks are struck through in the track table — their
255
317
  numbers are never reused.
256
318
 
319
+ Every review dispatch carries a track intention block with four
320
+ fields: target, scope boundary, deferred work, and acceptance
321
+ condition.
322
+
257
323
  Per-track sequence:
258
324
 
259
325
  1. Implement the track, following the project's own engineering
260
- guidelines for commit/test/push discipline.
326
+ guidelines for commit/test/push discipline. An implementation
327
+ commit body states what had to be implemented, then how the result
328
+ differs and why. It never restates the diff.
261
329
  2. MANDATORY agent code review of the cumulative track diff
262
330
  `git diff <prev-marker>..HEAD` — correctness, test coverage, style,
263
331
  API surface, documentation sync — composed per review-rules.md in
264
- this directory.
265
- 3. Fix findings as normal commits.
332
+ this directory. Skip this step only when the WHOLE change is
333
+ trivial. No track inside a medium or higher change is trivial.
334
+ 3. Fix findings and handle suggestions under review-rules.md §5. Record
335
+ each suggestion as a standalone entry in the log's Suggestions
336
+ section.
266
337
  4. MANDATORY user review: present the track summary and the track diff
267
338
  to the user, then loop on user feedback — landing fixes as normal
268
339
  commits — until the user explicitly approves. The agent waits for
269
340
  that approval; the marker commit certifies a fully user-reviewed
270
341
  track.
271
- 5. Land the marker commit.
342
+ 5. Land the marker commit when the change has more than one track.
272
343
  6. Update the track's row in the track table (status, scope drift);
273
- revise the planned-changes statement only if reality diverged from
274
- it.
344
+ revise the high-level design only if reality diverged from it.
345
+
346
+ ### Internal review loops and escalations
347
+
348
+ The adversarial and agent code review loops are internal to the
349
+ orchestrator. The orchestrator asks the user only for a decision it
350
+ cannot make. review-rules.md §6 owns the escalation list.
275
351
 
276
352
  ### Track table
277
353
 
@@ -280,7 +356,7 @@ display-only index of the split: track names, one-line scopes,
280
356
  statuses — never commit SHAs, and never the source of truth for track
281
357
  boundaries (marker commits are, see § Marker commits). It lives in the
282
358
  umbrella PR description when publishing is enabled and in the workflow
283
- log's Track table section when it is disabled.
359
+ log's Track table section in both modes.
284
360
 
285
361
  ## Marker commits (source of truth for track boundaries)
286
362
 
@@ -309,7 +385,7 @@ Properties:
309
385
  - The track table is never an alternative source of truth for
310
386
  boundaries (constraints owned by § Track table).
311
387
 
312
- Single-track changes land no markers — the whole branch diff is the
388
+ A change with one track lands no marker — the whole branch diff is the
313
389
  track.
314
390
 
315
391
  ## Rebase note
@@ -326,14 +402,25 @@ via a doctrine extension (the `doctrineExtraPath` key in the project's
326
402
  `slate.json`). A layered peer review supplements, never replaces, the
327
403
  mandatory per-track user review.
328
404
 
405
+ ## Migration
406
+
407
+ A change whose high-level design was approved under the previous rules finishes
408
+ under those rules. The new rules apply to a change started after the
409
+ upgrade. When the previous document text is no longer installed, the
410
+ log's recorded rule-set version and gate list are the authority.
411
+
329
412
  ## Layering richer workflows on top
330
413
 
331
414
  Richer internal planning and execution machinery — whatever agent
332
415
  tooling is in use — may be layered on top of this baseline, provided
333
- it satisfies the mandatory gates: a user design review before
334
- adversarial review, pre-implementation adversarial review, an agent
335
- code review per track, a mandatory user review per track, marker
336
- commits at track boundaries, and — when draft-PR publishing is
337
- enabled — the obligations of pr-publishing.md (umbrella draft PR
338
- before coding starts, user-performed merge). This document defines the
339
- baseline that applies regardless of the tooling.
416
+ it satisfies the mandatory gates for the confirmed class: a
417
+ high-level design for medium and above; high-level design presentation
418
+ before adversarial review for complex and risky; high-level design
419
+ presentation before implementation for medium and above; adversarial
420
+ review of the high-level design
421
+ for complex and risky; a research log for medium and above; agent code
422
+ review for every track unless the whole change is trivial; mandatory
423
+ user review of every track diff; marker commits at multi-track
424
+ boundaries; and, when draft-PR publishing is enabled, the obligations
425
+ of pr-publishing.md. This document defines the baseline that applies
426
+ regardless of the tooling.
@@ -127,8 +127,11 @@ not test idea count. The reminder then includes this exact scope guard:
127
127
 
128
128
  `Exclude research logs, worker task text, and the project's own agent instruction file.`
129
129
 
130
- This guard prevents the five requirements from applying to those
131
- excluded artifacts.
130
+ This guard is a coarse summary wherever Slate renders it, including the
131
+ doctrine rule and the reminder. The summary names research logs as excluded.
132
+ When `writing.check` is true, the high-level design remains governed even
133
+ while it lives inside a research log. This document is the authority on the
134
+ precise scope of every rendering.
132
135
 
133
136
  These requirements are not mechanical checker findings. The shipped
134
137
  checker has no rule for idioms or bare-reference openers. It also has
@@ -441,4 +444,6 @@ These are settled decisions. Read them as scope, not as a backlog.
441
444
  review comments, release notes and messages to the user. Research
442
445
  logs, worker task text and this repository's own agent instruction
443
446
  file are excluded, because a dense exact register serves them
444
- better.
447
+ better. When a project sets `writing.check` to true, its high-level
448
+ design is governed prose even while it lives inside an otherwise
449
+ excluded research log.
@@ -35,7 +35,7 @@
35
35
  * "contextBudget": 256000, "orchestratorModeDefault": true,
36
36
  * "orchestratorPromptDocs": ["docs/orchestrator-guidelines.md"],
37
37
  * "workerPromptDocs": ["docs/thread-guidelines.md"],
38
- * "workflow": { "draftPRs": false },
38
+ * "workflow": { "draftPRs": false, "followUpIssues": false },
39
39
  * "modelFailover": { "provider/id": "provider/id" },
40
40
  * "preserveGlobalModelDefault": true,
41
41
  * "doctrineExtraPath": "docs/project-doctrine.md",
@@ -74,6 +74,7 @@ import {
74
74
  sanitizeCacheKeyEnabled,
75
75
  sanitizeCacheKeyShards,
76
76
  sanitizeEpisodeModel,
77
+ sanitizeWorkflowConfig,
77
78
  SlateStore,
78
79
  type SlateConfig,
79
80
  } from "./state.ts";
@@ -205,6 +206,7 @@ export default function (pi: ExtensionAPI) {
205
206
  // and reported itself as a configuration fault.
206
207
  showRouterWarnings = config.router.showWarnings === true;
207
208
  config.writing = sanitizeWritingConfig(config.writing, warn);
209
+ config.workflow = sanitizeWorkflowConfig(config.workflow, warn);
208
210
  // episodeModel too (RG20): an unusable value falls back to the built-in
209
211
  // compressor, and until this ran it did so without saying anything at all.
210
212
  config.episodeModel = sanitizeEpisodeModel(config.episodeModel, warn);
package/extension/mode.ts CHANGED
@@ -460,6 +460,9 @@ function buildDoctrine(
460
460
  publishing mechanics are in ${PR_PUBLISHING_DOC}.`
461
461
  : `Durable workflow records anchor in the retained repo-root workflow
462
462
  log per the workflow doc.`;
463
+ const followUpTail = trusted && config.workflow?.followUpIssues === true
464
+ ? "\n After review, ask the user which review suggestions become tracker issues."
465
+ : "";
463
466
  const perspectives = config.reviewPerspectivesPath;
464
467
  const rule9Tail =
465
468
  trusted && typeof perspectives === "string" && perspectives && existsSync(resolve(cwd, perspectives))
@@ -484,7 +487,9 @@ threads execute. Rules:
484
487
  With acting off, omit it for no permission or supply it for a reported choice. \`[]\`
485
488
  refuses a restart and preserves the live transcript. A non-empty list of existing
486
489
  episode ids permits a restart and seeds the new thread. Slate restarts only when
487
- cheaper. Continue the successor. Details: ${THREAD_CACHE_COST_DOC}
490
+ cheaper. A blanket refusal of a thread restart has a price. Refuse only when the
491
+ next action depends on context from the previous action that the thread's episodes
492
+ do not carry. Continue the successor. Details: ${THREAD_CACHE_COST_DOC}
488
493
  4. Compose context by reference: pass prior episode ids in \`context\` instead
489
494
  of restating their content.
490
495
  5. Your read-only tools (read/grep/find/ls) are for cheap orientation only;
@@ -492,16 +497,18 @@ threads execute. Rules:
492
497
  6. After every episode, update your strategy. Episodes marked STATUS: FAILED
493
498
  require adaptation, not blind retry.
494
499
  7. Keep your own messages strategic: goals, task routing, synthesis.
495
- 8. Repository changes follow the slate track-based workflow — read
496
- ${TRACK_WORKFLOW_DOC}
497
- (skip the read if it is already in your context). Before the FIRST
498
- dispatch that modifies files, confirm the pre-implementation gates ran
499
- (user design review, adversarial review, user-approved scope).
500
+ 8. Scale change gates by class: trivial, medium, complex, or risky. The
501
+ orchestrator owns the track split. For repository changes, read
502
+ ${TRACK_WORKFLOW_DOC} (skip the read if it is already in your context). Above trivial, keep a research log. Every track diff requires
503
+ user review. Before the first file-modifying dispatch, confirm the user confirmed
504
+ the class and all required pre-implementation gates ran. Medium and above require
505
+ user-approved design. Complex and risky then require adversarial design review,
506
+ then final user approval.
500
507
  ${rule8Tail}
501
508
  9. Every non-trivial change gets reviewed before it is declared done.
502
509
  Before dispatching review threads, read
503
510
  ${REVIEW_RULES_DOC}
504
- (skip the read if it is already in your context) and follow it.${rule9Tail}
511
+ (skip the read if it is already in your context) and follow it.${rule9Tail}${followUpTail}
505
512
  10. The design principles behind this architecture are documented in
506
513
  ${DESIGN_PRINCIPLES_DOC}.
507
514
  Read that file only when you must reason about slate itself (explaining
@@ -847,6 +847,52 @@ export interface ThreadChoiceConfig {
847
847
  act?: boolean;
848
848
  }
849
849
 
850
+ /** Optional raw workflow publishing and follow-up issue controls. */
851
+ export interface WorkflowConfig {
852
+ draftPRs?: boolean;
853
+ followUpIssues?: boolean;
854
+ }
855
+
856
+ /** Sanitized workflow shape. draftPRs stays unvalidated until issue 164 resolves it. */
857
+ export interface SanitizedWorkflowConfig {
858
+ draftPRs?: unknown;
859
+ followUpIssues: boolean;
860
+ }
861
+
862
+ /** Display a rejected workflow value without letting serialization abort session startup. */
863
+ function quotedWorkflowValue(value: unknown): string {
864
+ let text: string | undefined;
865
+ try {
866
+ text = JSON.stringify(value);
867
+ } catch {
868
+ text = undefined;
869
+ }
870
+ if (text === undefined) {
871
+ try {
872
+ text = String(value);
873
+ } catch {
874
+ text = `[unprintable ${typeof value}]`;
875
+ }
876
+ }
877
+ return sanitizeForNotify(text);
878
+ }
879
+
880
+ /** Validate the follow-up issue switch while preserving an own draft publishing value. */
881
+ export function sanitizeWorkflowConfig(raw: unknown, warn: (msg: string) => void): SanitizedWorkflowConfig {
882
+ if (raw === undefined) return { followUpIssues: false };
883
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return { followUpIssues: false };
884
+ const value = raw as { draftPRs?: unknown; followUpIssues?: unknown };
885
+ const hasOwn = (key: "draftPRs" | "followUpIssues") => Object.prototype.hasOwnProperty.call(value, key);
886
+ const draftPRs = hasOwn("draftPRs") ? { draftPRs: value.draftPRs } : {};
887
+ const candidate = hasOwn("followUpIssues") ? value.followUpIssues : undefined;
888
+ if (candidate === undefined) return { ...draftPRs, followUpIssues: false };
889
+ if (typeof candidate === "boolean") return { ...draftPRs, followUpIssues: candidate };
890
+ warn(
891
+ `slate: ignoring workflow.followUpIssues ${quotedWorkflowValue(candidate)}. Expected true or false. Slate uses false.`,
892
+ );
893
+ return { ...draftPRs, followUpIssues: false };
894
+ }
895
+
850
896
  /** Optional writing checks and context-cadenced reminders. */
851
897
  export interface WritingConfig {
852
898
  check?: boolean;
@@ -866,7 +912,7 @@ export interface SlateConfig {
866
912
  orchestratorModeDefault?: boolean; // seed orchestrator mode ON for fresh interactive sessions (unsaved until first real mutation)
867
913
  orchestratorPromptDocs?: string[]; // role-guideline docs appended to the orchestrator prompt (cwd-relative paths, default none)
868
914
  workerPromptDocs?: string[]; // role-guideline docs appended to worker system prompts (cwd-relative paths, default none)
869
- workflow?: { draftPRs?: boolean }; // draftPRs: umbrella draft PRs are part of the pre-implementation gates (default false)
915
+ workflow?: WorkflowConfig | SanitizedWorkflowConfig; // raw or session-sanitized workflow controls (both default false)
870
916
  modelFailover?: Record<string, string>; // model→model failover map ("provider/id" → "provider/id"); empty/absent = feature off
871
917
  preserveGlobalModelDefault?: boolean; // restore the user's GLOBAL pi model defaults (defaultProvider/defaultModel/defaultThinkingLevel) after a slate-initiated model switch — failover and handoff adoption (default true; only an explicit false disables it) — see model-default.ts
872
918
  doctrineExtraPath?: string; // cwd-relative markdown appended to the orchestrator doctrine (project-doctrine section)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ytdb-slate",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Slate: thread-weaving orchestration for the pi coding agent — bounded worker actions, compressed episodes, mandatory research/design/adversarial/track review workflow, configurable model failover, and orchestrator context-budget handoff.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {