@deftai/directive-content 0.109.1 → 0.110.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.
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: deft-directive-triage
3
3
  description: >-
4
- Triage-cache hygiene and "what's next?" queue selection -- the agent-facing
5
- playbook for syncing the triage cache, classifying candidates, presenting a
6
- ranked queue, walking per-item decisions, and auditing the session.
4
+ Withdrawn (#4070). Classify playbook is off. Work selection is
5
+ plan-sequence:current then a read-only triage:queue listing. Replacement
6
+ sieve is #4071. Triggers still match so packs:slice finds this stub.
7
7
  ---
8
8
 
9
9
  Read and follow: skills/deft-directive-triage/SKILL.md
package/Taskfile.yml CHANGED
@@ -992,12 +992,19 @@ tasks:
992
992
  CLI_ARGS: "{{.CLI_ARGS}}"
993
993
 
994
994
  triage:classify:
995
- desc: "Inspect / validate auto-classification + Tier-1 SCM label mirror (#1129 / #1423). -- task triage:classify -- [--list | --validate | --mirror [--apply]]"
995
+ desc: "Inspect / validate auto-classification. --mirror is withdrawn (#4070). -- task triage:classify -- [--list | --validate]"
996
996
  cmds:
997
997
  - task: triage-classify:classify
998
998
  vars:
999
999
  CLI_ARGS: "{{.CLI_ARGS}}"
1000
1000
 
1001
+ triage:strip-withdrawn-chips:
1002
+ desc: "Remaining-set strip of withdrawn triaged / triage:* chips (#4070). -- task triage:strip-withdrawn-chips -- [--apply] [--emit-digest] [--json] [--repo OWNER/NAME]"
1003
+ cmds:
1004
+ - task: triage-classify:strip-withdrawn-chips
1005
+ vars:
1006
+ CLI_ARGS: "{{.CLI_ARGS}}"
1007
+
1001
1008
  triage:summary:
1002
1009
  desc: "Emit the one-line triage state for the session-start ritual (D2 / #1122). Always exits 0; appends a JSONL record to <lifecycle-root>/.triage-cache/summary-history.jsonl. -- task triage:summary -- [--json] [--no-history]"
1003
1010
  cmds:
package/commands.md CHANGED
@@ -309,7 +309,7 @@ Current status: the validation, extractor, provider, registry, generated MAP, an
309
309
  - `task verify:orphan-active -- --changed-only [--base-ref <ref>]` -- the merge-chokepoint form composed into `check:framework-source` / `check:consumer` (#3893). It evaluates only the active/running briefs the candidate's own diff touches, so a brief stranded by another merge cannot fail an unrelated PR and N stranded briefs no longer make N single-brief lifecycle PRs mutually unmergeable. Base ref defaults to `origin/<deliveryBranch>`. It falls back to the full repo-wide sweep -- never to a narrower scan -- when HEAD is on the delivery line (the delivery-tip check) or when git or the base ref is unresolvable, and every run prints which scope it used. Mutually exclusive with `--issue N` (exit 2). The bare verb stays repo-wide for `deft doctor`, manual runs, and swarm finalize.
310
310
  - `task verify:pr-closeout-attestable -- --pr N` -- fail closed when merging PR `N` would close an issue whose brief is still `running` in `xbrief/active/` with acceptance criteria carrying neither `x-directive/evidence` nor `x-directive/disposition` (#3781). The trigger is the PR's structured closing references, **not** the branch diff: CI runs before the merge and the issue closes on it, so a diff-keyed gate can never fail the PR that creates the orphan, and the brief need not be in the diff at all. Reuses `evaluateAcceptanceEvidenceGate`, the same rule `scope:complete` enforces. The refusal names each unattested criterion and the exact shape it needs, narrowed to the evidence kinds that criterion's axis allows. A PR that leaves an unattested brief **without** closing its issue is unaffected. Reads the working tree at `--project-root`, which at merge time is the PR head checkout. Matching is repository-qualified and case-insensitive on the owner/repo slug: closing references are scoped to the PR's repository, so a same-numbered issue tracked by a brief in another repository cannot block the merge, a mixed-case slug for this repository still matches, and a bare tracking number reads as this repository. Three-state exit (0 attestable or closes nothing / 1 unattested closeout / 2 config or lookup error) -- an unresolved closing-reference lookup, or an unresolvable OWNER/REPO, is 2, never a pass. `task pr:wait-mergeable-and-merge` runs it as the last gate before the merge call.
311
311
  - `task verify:lifecycle-visible` -- warn when a clone's ignore configuration hides `xbrief/` / `vbrief/` lifecycle roots (#3505). Uses `git check-ignore -v` on the stage dirs, a matching-extension sentinel under each, and bounded probes derived from ignore-rule globs in root, exclude, `core.excludesFile`, and nested lifecycle `.gitignore` files (so `2026-06-*.xbrief.json` / `2025-*.xbrief.json` cannot report clean), plus `git ls-files -v` for skip-worktree / assume-unchanged. Names the matching rule and source file. Warn-first from `session:start` (per-clone, not on `task check`). Selective `.triage-cache/*.jsonl` entries do not trip. Pass `--enforce` to fail closed.
312
- - `task verify:completed-write-guard` -- fail closed when a newly added `xbrief/completed/` (or `vbrief/completed/`) artifact was not written by `scope:complete` / `scope:fail` (#3679). Artifacts larger than 1 MiB fail closed before read. Historical corpus is advisory via doctor. Remediation names the leftover land PR after a scope-provenance strip (#3476). `scope:complete` can stamp a brief already in `completed/`. Does not change `verify:completed-tracked`.
312
+ - `task verify:completed-write-guard` -- fail closed when a newly added `xbrief/completed/` (or `vbrief/completed/`) artifact was not written by `scope:complete` / `scope:fail` (#3679), or when a change set deletes or renames away an `xbrief/active/` brief with no paired stamped destination (#3766). Same name-status parser covers A, R, and D. Terminal moves pass as `R active->completed` or `D active` plus `A completed` when the destination has a runTransition stamp. A `cancelled/` destination pairs only when it carries a `lifecycleWrite` cancel stamp. Delete-plus-add pairing also requires the dest `plan.title` to match the deleted source so a copied stamp cannot authorize an unrelated brief. Lone-D untracking cleanup halts and names `scope:complete` or leaving the brief untracked. Artifacts larger than 1 MiB fail closed before read. Historical corpus is advisory via doctor. Remediation names the leftover land PR after a scope-provenance strip (#3476). `scope:complete` can stamp a brief already in `completed/`. Does not change `verify:completed-tracked`.
313
313
  - `task verify:completed-tracked` -- fail closed when closed scoped issues lack a tracked `xbrief/completed/` or `xbrief/cancelled/` artifact on the delivery tip (#3264 / #3476); remediate with `task swarm:finalize-cohort` or a lifecycle PR. `task verify:completed-tracked -- --issue N` is the drive-to DONE form (delivery tip `origin/<deliveryBranch>`, not feature HEAD). Standalone verb (not part of `task check`); use `--tip HEAD` when validating an in-flight land branch. An unresolvable delivery tip fails closed (no silent HEAD fallback) -- fetch the delivery branch or pass an explicit `--tip`. Under `--skip-gh`, a named `--issue` with no cached state fails closed; the unscoped corpus scan keeps the offline allowance. Lifecycle-only lands (completed/cancelled xBRIEFs + optional CHANGELOG) use that verb plus finalize-cohort or the lifecycle PR. ⊗ Full `task check` / the TypeScript suite. ⊗ The drive-to story envelope (pre-pr + review-cycle + suite) for a file-copy land.
314
314
  - `task verify:ac` -- product-first acceptance gate (#3284). Runs `plan.acceptance.commands` (or #3267 literal ledger) **verbatim** before done; records AC-source rung (`stated`/`derived`/`project_floor`). Empty commands require `none_stated: true`. Empty resolution is not a green run when the project has no suite floor (`soft_empty` + stamp-acceptance remedy, #3334). Primary name used first in `task check` (fail-fast); `--soft-missing-xbrief` for check composition. Rapid ceremony = AC-only; pressure/degraded makes hygiene advisory. `--capture-only` lists resolved commands without executing. Extends #3267 / #973.
315
315
  - `task verify:literal-ac` -- #3267 mechanism alias for verbatim stated-command run (same flags/cwd); prefer `verify:ac` for product-first done-gate.
@@ -414,7 +414,7 @@ After CLI/deposit upgrade, disk can show the new generation while a long-lived s
414
414
  - ! **USER.md path (#2544):** resolve via `deft session:start` output (`USER.md resolved …`); default platform paths: Windows `%APPDATA%\deft\USER.md`, Unix `~/.config/deft/USER.md`; override `$DEFT_USER_PATH`; workspace `<project>/.deft/USER.md`. ⊗ Invent or search `~/.config/deft` on Windows — AppData Roaming is canonical.
415
415
  - ! At mutation boundaries (code-writing, scope lifecycle moves, `start_agent`, commits, pushes, PR-from-local-changes, release work): run the mutable quick tier then gated verifier below before proceeding.
416
416
  - ? Explicit read-only alignment only: `deft session:start -- --read-only` (no ritual-state write).
417
- - ! **Worktree occupancy contract (#3433 / #3604 / #3611):** mutation `session:start` / `session:ready` claim a gitignored `.deft/occupancy.json` lease. Occupancy is cooperative host-session routing between processes that follow the protocol, not authentication against another same-user process: hook JSON and local owner IDs are forgeable. Name it for what it is (#3755): a **cooperative bearer-id boundary, not a lineage** — the lease admits whoever presents an id the record itself names, nothing observes parentage, and a dispatched child is admitted only because a grant records it. A live lease allows only a matching presented owner or member and a ritual state whose exact verified owner agrees; missing, conflicting, or mismatched identity fails closed. `--read-only` does not claim.
417
+ - ! **Worktree occupancy contract (#3433 / #3604 / #3611 / #3926):** mutation `session:start` / `session:ready` claim a gitignored `.deft/occupancy.json` lease. Occupancy is cooperative host-session routing between processes that follow the protocol, not authentication against another same-user process: hook JSON and local owner IDs are forgeable. Name it for what it is (#3755): a **cooperative bearer-id boundary, not a lineage** — the lease admits whoever presents an id the record itself names, nothing observes parentage, and a dispatched child is admitted only because a grant records it. A live lease allows only a matching presented owner or member and a ritual state whose exact verified owner agrees; missing, conflicting, or mismatched identity fails closed. `--read-only` does not claim. A stored lease whose `worktree_path` is not this checkout is residue, not a holder: first mutation `session:start` claims over it. Same-tree two-session conflict still fails closed.
418
418
  - ! **Which tree the lease is read from — root admission (#3794 / #4013):** a gated write is judged against the Git working tree its **target** lands in, not always the tree the host payload names. A target in another worktree sharing `--git-common-dir` is admitted and carries occupancy, ritual and active scope with it; a proven different repository, an unreadable target identity, and a mutation spanning two worktrees are refused. A target with **no Git toplevel at all** (OS temp, a home file, anything outside every checkout) is gated against the payload root — deliberate since #3794, published with its reason and a gate-by-gate disposition in [docs/hook-root-admission.md](./docs/hook-root-admission.md), which also records the three-surface matrix (direct write consults admission; generic server-prefixed MCP and out-of-repo Shell writes do not) and the relative-target canonicalization limitation (#4023).
419
419
  - ! **Host owner namespaces (#3611):** canonical owners are `host:<provider>:v1:<base64url(raw-id)>`. Codex uses payload `session_id` for the parent and its subagents. Claude Code uses `session_id`; `agent_id` does not replace the session-family owner. Cursor uses `conversation_id` and requires a simultaneously supplied `session_id` to agree; no Cursor subagent-granularity claim is made until verified. Grok has no verified payload identity, so its owner is the hook process variable `GROK_SESSION_ID` the host publishes (#3873): the hook is a sibling the host spawns, so an agent shell export cannot reach it, and the payload `session_id` is never read. When that variable is absent the host keeps explicit `--session-id` / `DEFT_SESSION_ID` ownership; a malformed one fails closed, as does an ambient `DEFT_SESSION_ID` that contradicts a resolved host owner.
420
420
  - ! **Occupancy identity on a host with no session derivation (#3877):** the hook process environment (`GROK_SESSION_ID` on Grok, or `DEFT_SESSION_ID` inherited by the hook) or an explicit `--session-id`. ⊗ a worker-shell `export DEFT_SESSION_ID`. A shell export reaches vitest, CLI verbs, and `scope:complete`; it never reaches `deft-hook`, a sibling process. Nothing in `content/templates` or `content/skills` mentions the variable. Do not invent an envelope mandate.
@@ -564,7 +564,7 @@ User-facing surface for the Phase 0 triage workflow and the unified content cach
564
564
 
565
565
  Directive does not guess your mix. Either you name the next units in order (**ordered plan**), or you let the ranked backlog suggest (**queue**). Labels bias the queue; they do not override an active plan.
566
566
 
567
- **See also (pre-promotion portfolio):** when the need is to cluster competing RFCs/issues into a propose-not-apply priority brief (not single-item queue ranking), use `skills/deft-directive-portfolio-priority/SKILL.md` (#3201 / #3198) classify is filter-only; no SCM label writes.
567
+ **See also (pre-promotion portfolio):** when the need is to cluster competing RFCs/issues into a propose-not-apply priority brief (not single-item queue ranking), use `skills/deft-directive-portfolio-priority/SKILL.md` (#3201 / #3198). Classify `--mirror` is withdrawn (#4070); no SCM label writes from that skill.
568
568
 
569
569
  | Path | When | Who sets it | Bare "what's next?" means |
570
570
  |---|---|---|---|
@@ -592,11 +592,11 @@ Directive does not guess your mix. Either you name the next units in order (**or
592
592
  - `task triage:history -- <issue>` -- show decision history.
593
593
  - `task triage:reset -- <issue>` -- append a reset record so a candidate can be reconsidered.
594
594
  - `task triage:bulk-accept|bulk-reject|bulk-defer|bulk-needs-ac` -- apply predictable decisions over filtered cached candidates.
595
- - `task triage:summary`, `task triage:scope`, `task triage:scope-drift`, `task triage:subscribe`, `task triage:unsubscribe`, `task triage:classify`, `task triage:welcome`, and `task triage:smoketest` -- supporting workflow and onboarding commands.
596
- - `task triage:classify -- --mirror [--apply] [--re-enrich] [--include-closed] [--author LOGIN|@me] [--repo owner/name] [--batch-size N] [--delay-ms N] [--sample-limit N] [--json]` -- **Bootstrap mass-triage / Tier-1 SCM label mirror (#1423 Wave 1–2 / #3125, #3129, #3197).** Runs the existing classify engine over the github-issue cache and mirrors outcomes as labels (`triaged` idempotency marker + optional `plan.policy.triageLabelMirror.actionLabels`). **Default state filter is open-only** (opt-in `--include-closed` for closed archive stamps). Optional `--author` / `--author-mine` scopes plan/apply to matching `author.login` (AND with open-only; digest surfaces the filter) (#3129). Dry-run by default: operator digest with totals (scanned/planned/already_triaged/no_match/closed_skipped/author_skipped/errors), breakdown by **state / rule / action**, and samples (not a full dump as primary UX); `--json` includes the same aggregates. `--apply` writes via the SCM label client / repo-mutation boundary in **batches** (`--batch-size`, default 10) with **rate-limit delay** (`--delay-ms`, default 1000), reports partial failures, and is idempotent on re-run (already-`triaged` skip). **Re-run vs re-enrich (#3124 / #3197):** default re-run keeps the one-shot stamp (`skipped_already_triaged`). After `actionLabels` / auto-classify rule / hold-marker changes, opt in with **`--re-enrich`** (still dry-run by default; pair with `--apply` to write) to re-classify already-stamped issues and plan **additive** label deltas only (v1 never removes obsolete chips; never full reconcile). Digest distinguishes `kind=first-time` vs `kind=re-enrich` planned/applied rows (`planned_kind` / `re_enrich_planned`). Missing labels fail closed per issue with a create-label hint. **Never** calls `triage:accept` and **never** writes `proposed/` xBRIEFs. Wave 3 (agent Tier-2 comments) remains out of scope.
595
+ - `task triage:summary`, `task triage:scope`, `task triage:scope-drift`, `task triage:subscribe`, `task triage:unsubscribe`, `task triage:classify`, `task triage:strip-withdrawn-chips`, `task triage:welcome`, and `task triage:smoketest` -- supporting workflow and onboarding commands.
596
+ - `task triage:classify -- --mirror` -- **Withdrawn (#4070).** Dry-run and `--apply` both fail closed with a pointer at #4070. Replacement sieve is #4071. #3579 is transitively withdrawn for the gap. Do not close #1423, #3579, #2611, or #3923. `--list` / `--validate` remain. Strip leftover chips with `task triage:strip-withdrawn-chips` (remaining-set apply, not classify).
597
597
  - **Triage write-back pairing (#1423 / ADR-005).** When the author stamps that a lean is mechanism-shaped, write **both**: body-text field `mechanism-shaped: true` (the artifact) **and** mirrored label `design-critique:mechanism-shaped` (what `plan.policy.judgmentGates` matches and lists show). Do not compute the classification. No stamp -> the design-critique gate never fires. Clearance is a separate line on the thread: `design-critique: warranted | not warranted, because ...` -- engine evaluates presence, shape, and authority, never the because-clause content. Advisory/observe; `verify:judgment-gates --enforce` stays opt-in unused; `scope:promote` does not gain `--enforce` in this story.
598
598
  - **Design-critique catalog chip (#3642).** Parent attach of `triage-ready` / recut `mechanism-shaped` MUST use `task scm:issue:design-critique-chip -- --issue N --chip triage-ready|mechanism-shaped [--repo OWNER/NAME]` (or `deft scm issue design-critique-chip`). Closed catalog remaining-set replace, one write. ⊗ `gh api POST .../labels`. ⊗ additive `scm:issue:edit --add-label`.
599
- - **Operator discovery for SCM label mirror (#3124).** Cold `session:start` (via `triage:welcome` default mode) surfaces a **throttled** tip until the first successful `--mirror` dry-run or operator ack — **not** on every re-arm. Tip teaches existence **and** get-the-most: dry-run `deft triage:classify -- --mirror` (open-only; `--include-closed` opt-in); `--apply` batches writes and **never** auto-accepts into `proposed/`; defaults only stamp **`triaged` on matches** (control stamp, not disposition); **board usability is greatly decreased without `actionLabels`** — recommend full five-chip map (`defer→triage:deferred`, `archive→triage:archived`, `accept→triage:lifecycle-linked`, `escalate→triage:needs-human` + always `triaged`); more matches → `plan.policy.triageAutoClassify` in PROJECT-DEFINITION; inspect via `deft policy:show --field=plan.policy.triageLabelMirror`; labels must exist on GitHub; applying `triaged` before action chips skips re-enrichment on re-run (use `--re-enrich`); point at consumer kit **#2611** (`content/docs/consumer-issue-label-kit.md`) do not invent vocabulary. Dismiss without dry-run: `deft triage:classify -- --ack-discovery` (production entry for tip ack). Dry-run digests SHOULD footer-hint when `actionLabels` is empty or open `no_match` dominates. **Anti-swallow:** when the tip fires, agents MUST restate existence + get-the-most in the **user-visible** message (not absorb ceremony alone).
599
+ - **Operator discovery for SCM label mirror (#3124).** Withdrawn with classify `--mirror` (#4070). The session/welcome tip does not fire. #3124 discovery and #1423 Wave 1–2 apply are unusable after this lands; those issues stay open.
600
600
 
601
601
  ### Cache Tasks
602
602
 
@@ -155,10 +155,27 @@ panel-deposit
155
155
  round: 1
156
156
  siblings: 3
157
157
  input-ceiling: 5390001612
158
+ families: grok, claude, codex
159
+ ```
160
+
161
+ A sibling-seat record is an allowed substitute for the `families:` line:
162
+
163
+ ```text
164
+ seat: grok launcher: spawn_subagent
165
+ seat: claude launcher: claude
166
+ seat: codex launcher: codex
158
167
  ```
159
168
 
160
169
  **Panel completeness is behavioural.** The deposit MUST above, and every sibling-completeness clause in this document, bind the parent. No code observes them. `evaluateCompletedArcRecord` reads a deposit only as evidence that an arc is in flight; it never counts critic posts and never compares a count against `siblings:`. `evaluateParentAudit` carries no round, sibling, or deposit field. Both halves hold: the obligation on the parent is real, and nothing machine-checks it. A parent that binds on a partial panel breaks this contract and no gate will stop it (#3850).
161
170
 
171
+ **Seat families are a different check (#4067).** Completeness is still unobserved. Family composition is fail-closed over parent-claimed families and a PATH probe, not over live GitHub comments.
172
+
173
+ - ! For spend N≥3, the panel-deposit or a sibling-seat record names three claimed families before the first sibling spawn. Parent claims the family at dispatch. ⊗ Classify family from a model slug.
174
+ - ! A same-family sibling set is not a panel. ⊗ Lean it. Printed recovery is re-seat (or halt), not wait for Stop 5.
175
+ - ! Grok Build launcher tree: Grok seat via `spawn_subagent` (or `grok`); Claude seat via `claude` CLI; Codex seat via `codex exec`. Worktree isolation before each spawn. Probe `claude` / `codex` on PATH before offering paste-ready. Paste-ready is the fallback when a named family's CLI is absent. Close stdin on CLI spawns (Windows `cmd /c "… <nul"`; Unix `… </dev/null`). Pointer: [`docs/grok-build-subscription-setup.md`](../docs/grok-build-subscription-setup.md).
176
+ - ! `evaluatePanelSeatComposition` (`packages/core/src/design-critique/panel-seat-families.ts`) refuses a same-family N≥3 set and refuses paste-ready-first when `claude` / `codex` resolve. It takes claimed families and PATH probe results. It does not observe live comments and does not count siblings.
177
+ - ! After a dispatch-composition miss, offer a prevention issue. On yolo, file it. ⊗ Only re-seat.
178
+
162
179
  ### Comment lead (model then role)
163
180
 
164
181
  Comment-lead field. The first two lines of the triage write-back and of every critic, parent, and #3640 auto-posted comment name the LLM and the posting role. Keep the first line as `model: <slug>`. The second line is `role: triage|critic|parent`.
@@ -211,11 +228,14 @@ Keep the arc in this contract until a verified synthesis is accepted.
211
228
 
212
229
  - ! Each critic dispatch EXITs after posting.
213
230
  - ! Operator (or parent after an operator verb) dispatches the next envelope.
214
- - ! After each critic EXIT, parent posts a successor lean with proposed per-heading takes **before** printing `accept` / `retry differences` / `walk` / `walk all`. That posted lean is the first operator surface. Chat is not the record.
231
+ - ! After this round's same-round siblings are posted, parent posts a successor lean with proposed per-heading takes **before** printing `accept` / `retry differences` / `walk` / `walk all`. That posted lean is the first operator surface. Chat is not the record.
232
+ - ! Do not post the successor lean or print the verb menu while same-round siblings remain unposted. Spend is permission, not the wait rule. Parent dispatch bookkeeping is the trigger; thread posts corroborate.
233
+ - ⊗ Count self-attested `role: critic` lines as panel-complete.
215
234
  - ! Operator confirm or amend binds the proposed takes on that posted lean. Binding takes is not synthesis bind and does not stamp `design-critique:triage-ready`.
216
- - ⊗ Bind synthesis or stamp `design-critique:triage-ready` while same-round siblings remain unposted. The first lean after one critic EXIT is the take-offer, not the bind.
217
- - ! Later successor leans follow accept-X or walk-end, or land before synthesis. This supersedes #3627's "successor lean only after accept-X" for the first lean after critic EXIT. Later leans may still follow accept-X / walk-end.
218
- - ⊗ Print `accept` / `retry differences` / `walk` / `walk all` when no successor lean is posted for this critic EXIT. An empty-lean verb menu is a contract miss.
235
+ - ⊗ Bind synthesis or stamp `design-critique:triage-ready` while same-round siblings remain unposted. The first lean after this round's siblings are posted is the take-offer, not the bind.
236
+ - ! Later successor leans follow accept-X or walk-end, or land before synthesis. This supersedes #3627's "successor lean only after accept-X" for the first lean after this round's siblings are posted. Later leans may still follow accept-X / walk-end.
237
+ - ⊗ Print `accept` / `retry differences` / `walk` / `walk all` when no successor lean is posted for this round. An empty-lean verb menu is a contract miss.
238
+ - ! The halt line remains postable while same-round siblings remain unposted. An unposted sibling with no dispatch-fail evidence is Dual stop envelope exhaustion.
219
239
  - ⊗ Auto-dispatch critics (#3578 / #1702).
220
240
  - ⊗ Hand the arc to `triage:accept` / `scope:promote` until the completed-arc record is present: `design-critique: synthesis accepted, because …` citing the accepted successor lean (and the verified-claims table when posted). Catalog chips (`design-critique:mechanism-shaped` / `design-critique:triage-ready`) are list-visible convenience, not clearance. A lone synthesis-accepted-shaped comment that does not cite an accepted lean does not unblock ingest.
221
241
  - ⊗ Stamp `design-critique:triage-ready` at critic-post.
@@ -225,12 +245,13 @@ Keep the arc in this contract until a verified synthesis is accepted.
225
245
 
226
246
  ## Successor lean
227
247
 
228
- After each critic EXIT, parent posts a successor `**Lean:**` comment with proposed per-heading takes. That posted lean is the first operator surface. Later successor leans follow accept-X or walk-end, or land before synthesis.
248
+ After this round's same-round siblings are posted, parent posts a successor `**Lean:**` comment with proposed per-heading takes. That posted lean is the first operator surface. Later successor leans follow accept-X or walk-end, or land before synthesis.
229
249
 
230
- - ! After critic EXIT, post the successor lean before printing `accept` / `retry differences` / `walk` / `walk all`.
250
+ - ! After this round's same-round siblings are posted, post the successor lean before printing `accept` / `retry differences` / `walk` / `walk all`.
231
251
  - ! Lead that lean with the plain-language summary under the `## In plain English` token. The obligations are in `## Plain-language summary` below.
232
252
  - ! Operator confirm or amend is what makes those takes bindable. An all-accept draft still goes through this offer. Confirming or amending an all-accept first lean binds those takes. It does not auto-stamp synthesis or `design-critique:triage-ready` while same-round siblings remain unposted.
233
253
  - ! Cite accepted critic ids/headings, the still-open residual, and the write-back or prior lean it supersedes.
254
+ - ! A lean that closes a round of two or more names that round's dispatched sibling count and cites each sibling comment id it is leaning over.
234
255
  - ! Carry a per-heading take on the successor lean: `accept-into-contract` | `disagree` | `defer`. Defer is not accepted.
235
256
  - ! The successor lean is the disposition map. Do not post a third map type.
236
257
  - ! The first posted map is an ADR-006 arbitration surface. Record a substantiation token when takes introduce load-bearing premises. Non-self-arbitration applies when the same party authored the triage and the proposed takes.
@@ -328,7 +349,7 @@ audit:<id> sha=<git-sha> pointer=<path:start-end|comment:<id>> reading=measured|
328
349
 
329
350
  ## Operator verbs
330
351
 
331
- Contract stops stay internal. Parent prints these phrases when they apply. They apply only after a successor lean is posted for this critic EXIT. Printing the verb menu with no posted successor lean is a contract miss. The operator does not have to remember them.
352
+ Contract stops stay internal. Parent prints these phrases when they apply. They apply only after a successor lean is posted for this round. Printing the verb menu with no posted successor lean is a contract miss. The operator does not have to remember them.
332
353
 
333
354
  - **accept** (cite findings)
334
355
  - **retry differences**
@@ -446,7 +467,13 @@ Closed catalog (last chip wins): `design-critique:mechanism-shaped` (in-flight,
446
467
  - ⊗ `gh api POST .../labels` or additive `scm:issue:edit --add-label` for this facet.
447
468
  - ⊗ Intercept mixed `scm issue edit` adds/removes for this facet.
448
469
  - ⊗ General-purpose labels CLI.
449
- - ! After the completed-arc record is present, `triage:accept` / `scope:promote` / `issue:ingest` / build may proceed. Any identity may run those verbs. Same-session parent continuation is not required. GitHub Triage on the implementer is not required. They read the accepted verified synthesis (latest successor lean plus the verified-claims table).
470
+ - ! After the completed-arc record is present, `triage:accept` / `scope:promote` / `issue:ingest` / build may proceed unless `evaluateCompletedArcRecord` returns `cancelled` or `unrecut-body` (#4057). Any identity may run those verbs. Same-session parent continuation is not required. GitHub Triage on the implementer is not required. They read the accepted verified synthesis (latest successor lean plus the verified-claims table).
471
+ - ! Per-thread body ingest stays the mapper after a set-level bind. Stories the bind wants are recut bodies or newly filed issues. Derived AC stays on that body.
472
+ - ! Un-recut portfolio members fail closed on `cancelled`. Parent posts `design-critique: cancelled, because ...` on that number. Parent `role: parent` dominate prose is not that record. Critic, quoted, or fenced cancel-shaped prose is not that record. Leftover `mechanism-shaped` without cancel stays `missing-record` and is not this control.
473
+ - ! A later successor lean after cancel starts a recut arc. Completing a superseded thread without recut would mint the harvest.
474
+ - ! A complete record whose latest `target shape:` field is `set-level` is `unrecut-body`. Recut the body (and record a non-set-level shape) or file a new issue. Ingest the anchor only is not supported while that field remains set-level.
475
+ - ⊗ Select an author-blind latest successor lean as CurrentShape.
476
+ - ⊗ Put a set-level graph (dominate / split / corpus parsed from comment English) inside ingest.
450
477
  - ! Ingest clearance cites the latest successor lean. An older completed-arc record does not clear a later recut lean. A panel-deposit is in-flight even when the catalog chip missed and no critic has posted.
451
478
  - ! The lexical form of that citation, and the requirement that the occurrence be affirmative, are published in `## Citation grammar`. Ingest reads that grammar, not prose intent.
452
479
  - ! Keep `plan.policy.judgmentGates` matching only `design-critique:mechanism-shaped`. After `triage-ready` replaces it, the issue leaves the gate match.
@@ -516,7 +543,7 @@ The intake cross-ref scanners (`packages/core/src/intake/markdown-scanners.ts`)
516
543
  - ! Clearance is set membership: the record clears when the cited set contains the latest successor lean id. Position in the body does not select the lean, so citing the prior lean that `## Successor lean` requires cannot block.
517
544
  - ! A block detail reports what was scanned, what was found, and the accepted forms. ⊗ Guess at a cause. A guessed detail sends the operator back to re-post the same body and reproduce the refusal.
518
545
 
519
- `CompletedArcBlockReason` is closed. A block detail names one of these six:
546
+ `CompletedArcBlockReason` is closed. A block detail names one of these eight:
520
547
 
521
548
  | Reason | What it reports |
522
549
  | --- | --- |
@@ -526,6 +553,8 @@ The intake cross-ref scanners (`packages/core/src/intake/markdown-scanners.ts`)
526
553
  | `missing-table-cite` | a typed table claim names an id that is not a comment on this thread |
527
554
  | `unshaped-table-cite` | a typed table claim names a comment on this thread that opens no line with the verified-claims-table heading |
528
555
  | `ambiguous-table-cite` | two typed table claims name different tables |
556
+ | `cancelled` | `design-critique: cancelled, because ...` is the latest terminal record; no later successor lean |
557
+ | `unrecut-body` | completed-arc is present and the latest `target shape:` field is `set-level` |
529
558
 
530
559
  - ! Publish a reason in that table before the evaluator returns it. An unpublished reason code is the same gap as an unpublished citation form.
531
560
  - ⊗ Merge two states under one reason when their remedies differ. `missing-table-cite` and `unshaped-table-cite` were one reason and one detail until #3942, and the shared detail asserted an absent id in both, so an author whose table was on the thread read a true citation being called false and had no path to the missing heading.
@@ -547,4 +576,4 @@ This motion ingests untrusted issue threads by design.
547
576
 
548
577
  ## Test surface
549
578
 
550
- `packages/core/src/content-contracts/standards/design_critique_contract.test.ts` locks required pointer strings, the scaffolds framing, the comment-lead field as model then role from the closed set (not an issue label), the operator-gated loop (successor lean, operator verbs including walk / walk all, dual stop, halt line, exclusive remaining-set replace of the two catalog chips, #3640 auto-stamp on a non-empty all-accept map and no-stamp on stubs, first-lean recording obligation after critic EXIT), the parent-side substantiation token and independence rules, the Stop 1 exclusion (pre-critic premises outside the trigger) and `refutation-target:` field tokens rather than full body sentences, the composed auto-bind conjunct (all-accept map AND zero unresolved audit markers) at Operator verbs and Bind path 1, the variant-table evaluation rule (charter selection and spend permission evaluated independently), the critic-method heading and distinctive obligation tokens (exact class tokens, citations-are-claims, existing mechanisms, injection / swarm trigger nouns, failed-reviewer phrase, finding anatomy) rather than full body sentences, the brief-template forbidden-inputs list, and the thin router skill (existence, line cap, pointer resolution, no-normative-content). `evaluateParentAudit` locks the omission failure modes. This suite locks the SoT MUST and the thin skill pointer for the first-lean recording obligation, including the auto-stamp operator-confirm conjunct and the no-bind-while-unposted-same-round-siblings rule. `evaluateCompletedArcRecord` locks ingest on the completed-arc record rather than a catalog chip. It does not fail-close live parent turns. `packages/core/src/design-critique/citation-grammar.test.ts` locks the `## Citation grammar` closed set, the refused positions, and the diagnostics surface; `packages/core/src/design-critique/completed-arc-record.test.ts` locks one parser for both questions, set membership against the latest lean, and the observation-echoing block details (#3831). Runtime parent-turn detection only if `evaluateParentAudit` is extended; that extension is not required to ship the recording obligation. Panel completeness is locked as contract text only. No predicate observes it on a live arc (#3850). `### The arc` and its derived boundaries, the `### Target shape` axis with its twice-run caveat, and the two bind-path-2 non-empty refusals are locked as contract text (#3797). `## Plain-language summary` is locked the same way: the contract test pins the heading token, the MUST-not-SHOULD reasoning, the ADR-006 exemption and its limit, the non-normative marking, and the per-artifact reserved line-start matrix, and `packages/core/src/design-critique/reserved-line-starts.test.ts` exercises each of the three families on each artifact kind against the exported shape predicates and `evaluateCompletedArcRecord`. No predicate observes a summary on a live arc (#3929). `### Verified-claims table heading`, the closed reason vocabulary, and the re-measured line-start matrix are locked as contract text, and `completed-arc-record.test.ts` exercises the typed refusal partition: the two states, details that differ by more than the id, the untyped null table id, and the seven recorded live arc table ids (#3942).
579
+ `packages/core/src/content-contracts/standards/design_critique_contract.test.ts` locks required pointer strings, the scaffolds framing, the comment-lead field as model then role from the closed set (not an issue label), the operator-gated loop (successor lean, operator verbs including walk / walk all, dual stop, halt line, exclusive remaining-set replace of the two catalog chips, #3640 auto-stamp on a non-empty all-accept map and no-stamp on stubs, first-lean recording obligation after this round's siblings are posted), the parent-side substantiation token and independence rules, the Stop 1 exclusion (pre-critic premises outside the trigger) and `refutation-target:` field tokens rather than full body sentences, the composed auto-bind conjunct (all-accept map AND zero unresolved audit markers) at Operator verbs and Bind path 1, the variant-table evaluation rule (charter selection and spend permission evaluated independently), the critic-method heading and distinctive obligation tokens (exact class tokens, citations-are-claims, existing mechanisms, injection / swarm trigger nouns, failed-reviewer phrase, finding anatomy) rather than full body sentences, the brief-template forbidden-inputs list, and the thin router skill (existence, line cap, pointer resolution, no-normative-content). `evaluateParentAudit` locks the omission failure modes. This suite locks the SoT MUST and the thin skill pointer for the first-lean recording obligation, including the auto-stamp operator-confirm conjunct and the no-bind-while-unposted-same-round-siblings rule. `evaluateCompletedArcRecord` locks ingest on the completed-arc record rather than a catalog chip. It does not fail-close live parent turns. `packages/core/src/design-critique/citation-grammar.test.ts` locks the `## Citation grammar` closed set, the refused positions, and the diagnostics surface; `packages/core/src/design-critique/completed-arc-record.test.ts` locks one parser for both questions, set membership against the latest lean, and the observation-echoing block details (#3831). Runtime parent-turn detection only if `evaluateParentAudit` is extended; that extension is not required to ship the recording obligation. Panel completeness is locked as contract text only. No predicate observes it on a live arc (#3850). `evaluatePanelSeatComposition` locks claimed-family composition and PATH paste-ready-first; it is a fixture over claimed families, not a live sibling-count gate. `### The arc` and its derived boundaries, the `### Target shape` axis with its twice-run caveat, and the two bind-path-2 non-empty refusals are locked as contract text (#3797). `## Plain-language summary` is locked the same way: the contract test pins the heading token, the MUST-not-SHOULD reasoning, the ADR-006 exemption and its limit, the non-normative marking, and the per-artifact reserved line-start matrix, and `packages/core/src/design-critique/reserved-line-starts.test.ts` exercises each of the three families on each artifact kind against the exported shape predicates and `evaluateCompletedArcRecord`. No predicate observes a summary on a live arc (#3929). `### Verified-claims table heading`, the closed reason vocabulary, and the re-measured line-start matrix are locked as contract text, and `completed-arc-record.test.ts` exercises the typed refusal partition: the two states, details that differ by more than the id, the untyped null table id, and the seven recorded live arc table ids (#3942).
@@ -57,10 +57,29 @@ deft policy:show --field=runtimeAuthority
57
57
  ### Active-story seam
58
58
 
59
59
  The hook dispatcher loads `file_scope` from the implementation-eligible active xBRIEF
60
- path when `inspectActiveScope` reports one. Residual gaps (document, not silent):
60
+ path when `inspectActiveScope` reports one.
61
+
62
+ When more than one preflight-eligible artifact is in `xbrief/active/` (a cohort
63
+ sharing one tree), first-wins is **not** used: that would fence every worker to one
64
+ story's `file_scope` and over-permit the others (#4007). Bind the dispatched story:
65
+
66
+ - `DEFT_ACTIVE_SCOPE` (absolute, project-relative, or unique basename) must name
67
+ one eligible running brief; that path's `file_scope` is the story fence
68
+ - On win32, pin matching is case-insensitive (the filesystem is). POSIX pins stay
69
+ case-sensitive, and a backslash in a POSIX pin is a filename character, not a
70
+ separator
71
+ - Missing pin + multiple eligible → fail closed (`scope-not-ready`). Recovery: set
72
+ the pin, or keep one running brief in `xbrief/active/`
73
+ - A pin that does not name an eligible brief → fail closed
74
+
75
+ The filed `__tests__` matcher diagnosis is refuted: `matchAny` already admits that
76
+ exact path and `_` is literal. Do not invent a `__`-segment exception. Pre-`c99f6159`
77
+ worktree relativisation is a separate discriminator (the raw unedited deny string)
78
+ and is not closed here.
79
+
80
+ Residual gaps (document, not silent):
61
81
 
62
82
  - Host / worktree cannot identify the active story → story layer omitted; project fence still applies
63
- - Multiple active artifacts → first preflight-eligible path wins (same as scope gate)
64
83
  - Story JSON unreadable → story layer fail-open; project fence still applies
65
84
 
66
85
  Shell/MCP push/merge scopes remain project-only (`runtimeAuthority.scopes`); they are not
@@ -170,10 +189,12 @@ OS-temp dests and commands with no recognized dest (`git status`,
170
189
  - Destinations that are shell **variables** are not recovered. That is most
171
190
  logged shell: 1,089 of 1,131 calls were dynamic, compound, or emitted no
172
191
  target.
173
- - A **directory junction** created without elevation defeats `provablyExternal`:
174
- the path is lexically outside the root and its realpath is inside. That is
175
- **re-entry** polarity. `#3186` `assertProjectionContained` is **escape**
176
- polarity (in-tree dest whose realpath leaves the tree) and does not close it.
192
+ - A **directory junction** created without elevation is **re-entry** polarity.
193
+ `isInRepoShellWritePath` reuses `isOutsideProjectRootWrite` so a lexically-outside
194
+ dest whose realpath is inside the project is gated. `#3186` `assertProjectionContained`
195
+ remains **escape** polarity (in-tree dest whose realpath leaves the tree) and is
196
+ not this check. The hook still runs before the shell, so a link created between
197
+ check and write is TOCTOU.
177
198
 
178
199
  Fail-open at this predicate is the bound posture (#3997). Inverting it to
179
200
  fail-closed on dests the parser cannot prove external is that issue's refuted
@@ -109,10 +109,9 @@ https://github.com/deftai/directive/blob/master/content/docs/consumer-issue-labe
109
109
  - epic (rare multi-ship product root)
110
110
  - status:tracker, status:child
111
111
 
112
- ## Mirror (if using triage:classify -- --mirror)
113
- - triaged
114
- - optional action chips: triage:deferred, triage:archived
115
- (only if plan.policy.triageLabelMirror.actionLabels maps them)
112
+ ## Mirror (withdrawn #4070)
113
+ - `triage:classify -- --mirror` is withdrawn. Do not stamp `triaged` / `triage:*` from classify.
114
+ - Replacement sieve is #4071. Leave these names unused until the replacement recuts the catalog.
116
115
 
117
116
  ## Optional project routing (only if used)
118
117
  - security (advisory security review routing; not a merge gate)
@@ -126,16 +125,7 @@ Do not invent labels outside this file. Prefer existing names over twins.
126
125
 
127
126
  ## Optional: label mirror appendix
128
127
 
129
- After SCM label mirror Waves 1–2 (#1423 / #3125):
130
-
131
- | Topic | Guidance |
132
- |-------|----------|
133
- | Defaults | Mirror is available; on match it stamps **`triaged`** (idempotency). Action chips only when configured. |
134
- | Dry-run | `deft triage:classify -- --mirror` (open-only default). Review the digest before `--apply`. |
135
- | Apply | `deft triage:classify -- --mirror --apply` writes labels in batches; re-run is a no-op for already-`triaged` issues. |
136
- | More matches | Add rules under `plan.policy.triageAutoClassify` in `xbrief/PROJECT-DEFINITION.xbrief.json`. |
137
- | Richer chips | Set `plan.policy.triageLabelMirror.actionLabels` **and** create those GitHub labels first. |
138
- | Accept path | ⊗ Never auto-`triage:accept` / never auto-write `proposed/` from mirror. Accept stays an operator decision. |
128
+ After #4070, SCM label mirror Waves 1–2 (#1423 / #3125) are unusable. `deft triage:classify -- --mirror` (dry-run and `--apply`) fail closed. Strip leftover chips with `deft triage:strip-withdrawn-chips`. Replacement sieve is #4071. #2611 stays open. Accept stays an operator decision (`triage:accept` / ingest unchanged).
139
129
 
140
130
  Minimal policy sketch (clone and edit; broader triage field examples live in the framework repo at [`docs/example-project-definition.md`](https://github.com/deftai/directive/blob/master/docs/example-project-definition.md) — not deposited under `.deft/core/`):
141
131
 
@@ -166,13 +156,10 @@ Minimal policy sketch (clone and edit; broader triage field examples live in the
166
156
  }
167
157
  ```
168
158
 
169
- If you only want the default `triaged` stamp, you can omit `actionLabels` entirely.
170
-
171
- Validate with:
159
+ `triage:classify -- --mirror` is withdrawn (#4070). Do not add `triageLabelMirror` to stamp `triaged` / `triage:*`. Validate remaining classify rules with:
172
160
 
173
161
  ```bash
174
162
  deft triage:classify -- --validate
175
- deft triage:classify -- --mirror
176
163
  ```
177
164
 
178
165
  ---
@@ -221,5 +208,5 @@ Framework source / GitHub (browse when not in a deposit):
221
208
  ## Related reading
222
209
 
223
210
  - Maintainer taxonomy (do not import wholesale): [`.github/ISSUE_LABELS.md`](https://github.com/deftai/directive/blob/master/.github/ISSUE_LABELS.md) (#2609)
224
- - Label mirror behavior: deposit `.deft/core/commands.md` (or framework `content/commands.md`) / `deft triage:classify -- --mirror` (#1423, #3125)
211
+ - Label mirror withdrawn: deposit `.deft/core/commands.md` (or framework `content/commands.md`) / #4070 (do not run `deft triage:classify -- --mirror`)
225
212
  - Example PROJECT-DEFINITION triage fields: [`docs/example-project-definition.md`](https://github.com/deftai/directive/blob/master/docs/example-project-definition.md) (#1186; framework repo only, not deposited)
@@ -79,7 +79,7 @@ checks tools without rewriting consumer-managed files.
79
79
 
80
80
  If you are adopting Deft on a project that already has an issue tracker (existing repo, brownfield migration, an upstream bug list that has been accumulating), you do not have to start from an empty `xbrief/proposed/`. The refinement skill's **Phase 0 triage workflow** lets you walk an existing backlog locally, decide what to keep, and let only the **accepted** items land in `xbrief/proposed/`. Trigger words: **"triage"**, **"work the cache"**, **"pre-ingest"**, **"action menu"**.
81
81
 
82
- **Labels first:** capacity and triage matchers only help when labels exist. For a bare or thin label set, adopt the [consumer issue-label kit](./consumer-issue-label-kit.md) (#2611) before you rely on ranking or `triage:classify -- --mirror`.
82
+ **Labels first:** capacity and triage matchers only help when labels exist. For a bare or thin label set, adopt the [consumer issue-label kit](./consumer-issue-label-kit.md) (#2611) before you rely on ranking. `triage:classify -- --mirror` is withdrawn (#4070).
83
83
 
84
84
  ### Step 1 — Scoped first populate
85
85
 
@@ -0,0 +1,146 @@
1
+ # Grok Build subscription-only setup
2
+
3
+ Agent-facing playbook for a new maintainer. Paste this file (or issue [#4035](https://github.com/deftai/directive/issues/4035)) and say: follow this playbook. The human completes browser logins when the agent stops.
4
+
5
+ This is **host auth**, not Directive `session:start` and not product work in `deftai/directive`.
6
+
7
+ Legend (RFC2119): `!`=MUST, `~`=SHOULD, `⊗`=MUST NOT.
8
+
9
+ ---
10
+
11
+ ## Goal
12
+
13
+ Grok Build is the parent on SuperGrok (`grok login` / grok.com). Claude Code and Codex run only through their CLIs on subscriptions. Console API keys may still exist at User scope for other tools. Grok must not use those keys.
14
+
15
+ ## Target shape
16
+
17
+ Verified 2026-08-31 on win32 (Grok 4.6 parent). Org names differ per maintainer. The auth *methods* must match.
18
+
19
+ | Surface | Required auth | Must not use |
20
+ |---|---|---|
21
+ | Grok Build parent | grok.com / `auth.x.ai` OIDC session (`grok login`) | `XAI_API_KEY`, `GROK_CODE_XAI_API_KEY`, Console BYOK `[model.*]` |
22
+ | Claude Code CLI | `claude.ai` team subscription (`claude auth login --claudeai`) | `ANTHROPIC_API_KEY` / `apiKeySource=ANTHROPIC_API_KEY` |
23
+ | Codex CLI | ChatGPT (`codex login status` → ChatGPT) | `OPENAI_API_KEY` |
24
+
25
+ Grok catalog (`grok models`) is only `grok-4.6` / `grok-4.5`. Default is `grok-4.6`.
26
+
27
+ User-scope `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` may remain for non-Grok tools. Leave them set.
28
+
29
+ ## Hard stops
30
+
31
+ The agent MUST NOT:
32
+
33
+ - implement product code while running this playbook
34
+ - unset User-scope or Machine-scope `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `XAI_API_KEY`
35
+ - run `claude logout`, `codex logout`, or `grok logout`
36
+ - add or restore BYOK `[model.*]` blocks in `~/.grok/config.toml` (opus / sonnet / fable / gpt-5.6 Console ids)
37
+ - print secret values (print only `set=$true` / `set=$false`)
38
+ - invent `~/.config/deft` on Windows (#2544)
39
+
40
+ Config is read at Grok session start. After any `config.toml` edit, start a **new** Grok session. Mid-session children will not pick up `shell_environment_policy`.
41
+
42
+ Close stdin on CLI spawns: Windows `cmd /c "… <nul"`; Unix `… </dev/null`.
43
+
44
+ ## Playbook
45
+
46
+ ### 1. Grok Build
47
+
48
+ Install the Grok CLI. Put it on PATH.
49
+
50
+ Human (browser): `grok login` (grok.com / SpaceXAI OAuth at `auth.x.ai`).
51
+
52
+ Confirm: `grok models` prints `You are logged in with grok.com.` and lists only `grok-4.6` / `grok-4.5`.
53
+
54
+ ### 2. `~/.grok/config.toml`
55
+
56
+ Path: `~/.grok/config.toml` (Windows: `%USERPROFILE%\.grok\config.toml`).
57
+
58
+ Set:
59
+
60
+ ```toml
61
+ [models]
62
+ default = "grok-4.6"
63
+ default_reasoning_effort = "high"
64
+ web_search = "grok-4.6"
65
+
66
+ # Grok Build must not meter Anthropic/OpenAI/xAI Console API.
67
+ # Claude/Codex go through their CLIs (subscription).
68
+ # User/Machine env keys stay for other tools; Grok shells do not inherit them.
69
+ [shell_environment_policy]
70
+ exclude = [
71
+ "ANTHROPIC_API_KEY",
72
+ "OPENAI_API_KEY",
73
+ "XAI_API_KEY",
74
+ "GROK_CODE_XAI_API_KEY",
75
+ ]
76
+ ```
77
+
78
+ Remove every `[model.<id>]` table that points at Anthropic or OpenAI Console (typical leftovers: `opus-5-high-fast`, `sonnet-5`, `fable-5`, `gpt-5.6-*`). Do not add new ones.
79
+
80
+ Do not copy unrelated `[ui]` personal settings from another maintainer.
81
+
82
+ Then start a **new** Grok session before the probes.
83
+
84
+ ### 3. Claude Code CLI
85
+
86
+ Install current Claude Code. On Windows a working layout is `~\.local\bin\claude.exe` plus shims (`~\.local\bin` and `%AppData%\npm` on PATH).
87
+
88
+ Human (browser): `claude auth login --claudeai`. Use the team org the operator names.
89
+
90
+ Confirm: `claude auth status` shows `loggedIn=true`, `authMethod=claude.ai`, `subscriptionType=team`, and **no** `apiKeySource=ANTHROPIC_API_KEY`.
91
+
92
+ ### 4. Codex CLI
93
+
94
+ Install Codex. On Windows the hashed binary may live under `%LOCALAPPDATA%\OpenAI\Codex\bin\`; keep a `codex` shim on PATH.
95
+
96
+ Human (browser): `codex login` (ChatGPT).
97
+
98
+ Confirm: `codex login status` prints `Logged in using ChatGPT`.
99
+
100
+ ### 5. PATH
101
+
102
+ User PATH includes `~/.local/bin` (Windows: `%USERPROFILE%\.local\bin`) so Grok children find `claude` and `codex` without extra env surgery.
103
+
104
+ ## Verification (report pass/fail with evidence)
105
+
106
+ Run from a **Grok** `run_terminal_command` child after the new session. Close stdin. Never print key values.
107
+
108
+ 1. **Catalog.** `grok models` → only `grok-4.6` / `grok-4.5`. Fail if opus / sonnet / fable / gpt-5.6 appear in *this* catalog (Codex may still say `gpt-5.6-*` as *its* ChatGPT model; that is not Grok BYOK).
109
+
110
+ 2. **Env policy.** This process may still have User keys. Print only `set=$true/$false` for User / Machine / Process scope of `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `XAI_API_KEY`, `GROK_CODE_XAI_API_KEY`. The Grok child Process-scope for `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` MUST be `$false`. Fail if the child still has them — policy did not apply (old session, or config not loaded). Do not delete User keys.
111
+
112
+ 3. **Claude from Grok, no extra unset.** `claude auth status` as above. Then:
113
+
114
+ `claude -p "Do not use tools. Reply with the single word: pong" --output-format text`
115
+
116
+ Fail on an API-key warning or not-logged-in.
117
+
118
+ 4. **Codex from Grok.** `codex login status` → ChatGPT. Then:
119
+
120
+ `codex exec --ephemeral --skip-git-repo-check --sandbox read-only "Do not use tools. Reply with the single word: pong"`
121
+
122
+ Fail if it demands `OPENAI_API_KEY`.
123
+
124
+ 5. **Grok itself.** The session model is `grok-4.6` (or `grok-4.5`), not a Claude id. `XAI_API_KEY` unset. Auth is grok.com session (`grok models` / `~/.grok/auth.json` `auth_mode=oidc` at `auth.x.ai`). Do not dump tokens from `auth.json`.
125
+
126
+ **Pass.** All five true. Grok Build is subscription-only: xAI login + Claude team + Codex ChatGPT. Keys may remain in User env for non-Grok tools.
127
+
128
+ **Fail.** Child shells still inherit `ANTHROPIC_API_KEY` (old session / policy not loaded) or Claude reports `apiKeySource=ANTHROPIC_API_KEY`. Do not delete User keys. Report and stop.
129
+
130
+ ## Design-critique dispatch
131
+
132
+ When a Grok Build parent runs an N≥3 design-critique panel, this playbook's CLIs are the other-family launchers. Probe `claude` / `codex` on PATH and CLI-spawn those seats. Paste-ready is the fallback when a CLI is absent, not the default recovery. Normative stop: [`contracts/design-critique.md`](../contracts/design-critique.md) Envelope and ceiling (#4067).
133
+
134
+ ## Out of scope
135
+
136
+ - [#4027](https://github.com/deftai/directive/issues/4027) — N≥3 design-critique lean-timing. This playbook is host auth. Do not launch a 3-panel unless the operator asks.
137
+ - [#2520](https://github.com/deftai/directive/issues/2520) — multi-engine least-privilege *pattern*. Related theme, different artifact.
138
+ - Unsetting User keys that other tools still need.
139
+ - Product code in `deftai/directive`.
140
+
141
+ ## Related Grok docs (local, after install)
142
+
143
+ - `~/.grok/docs/user-guide/02-authentication.md` — grok.com session vs `XAI_API_KEY` fallback
144
+ - `~/.grok/docs/user-guide/05-configuration.md` — `config.toml` precedence
145
+ - `~/.grok/docs/user-guide/11-custom-models.md` — BYOK `[model.*]` (do not add these)
146
+ - `~/.grok/docs/user-guide/18-sandbox.md` — `[shell_environment_policy]`
@@ -156,3 +156,29 @@ git add .deft/approved-scope/<plan-id>.json .deft/approved-scope/<plan-id>.inten
156
156
  ```
157
157
 
158
158
  Editing the xBRIEF alone does not authorize new implementation paths.
159
+
160
+
161
+ ## Cohort-created scope (operator mint at allocation) (#3874)
162
+
163
+ If a swarm cohort brief should declare `file_scope`, the operator who approved
164
+ the cohort mints the digest on a real TTY at allocation time and lands
165
+ `.deft/approved-scope/<plan-id>.json` on the merge base before workers activate.
166
+
167
+ - Allocation-context tokens (#1378) are **not** provenance.
168
+ - Swarm briefs are **not** exempt from this gate.
169
+ - `#3110` human-presence mint and merge-base layering are unchanged.
170
+
171
+ If the operator does not mint, omit `file_scope` when authoring the cohort brief.
172
+ Undeclared cohort briefs are then a deliberate outcome, not a post-failure
173
+ workaround. Do not undeclare a declared `file_scope` to pass the gate.
174
+
175
+ ## Working-tree / untracked files
176
+
177
+ `verify:scope-provenance` unions:
178
+
179
+ 1. `git diff --name-only <base>...HEAD`
180
+ 2. `git diff --name-only HEAD`
181
+ 3. `git ls-files --others --exclude-standard`
182
+
183
+ and lists on-disk `xbrief/active/` files. Presence in the working tree is what
184
+ matters. Committing or not committing the brief does not hide it from the gate.
@@ -1,6 +1,8 @@
1
1
  # Test / source boundary (`verify:test-boundary`)
2
2
 
3
- Refs: #3145 · Related: #1310 forward-coverage, testing layout guidance
3
+ Refs: #3145 · Related: #1310 / #4009 forward-coverage, testing layout guidance
4
+
5
+ `verify:forward-coverage` reuses this policy for source-to-test correspondence. It does not add a second testRoots config.
4
6
 
5
7
  ## Problem
6
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deftai/directive-content",
3
- "version": "0.109.1",
3
+ "version": "0.110.0",
4
4
  "deftConsumerDeposit": true,
5
5
  "description": "Shippable Directive framework content in the consumer .deft/core/ layout (C1 flatten), plus the engine surfaces (.githooks/, Taskfile.yml, tasks/) the deposit wires. Python-free per #2022 Phase 3. Refs #11, #1669, #1967.",
6
6
  "license": "MIT",