@deftai/directive-content 0.90.0 → 0.92.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.
@@ -0,0 +1,124 @@
1
+ # No in-band signaling / absence is not a decision (#1695)
2
+
3
+ Coding-standards pattern: do not overload one field (or its
4
+ presence/absence) to carry two orthogonal facts. Separate **value** from
5
+ **decision-provenance**. Triggered by the wipCap onboarding contradiction
6
+ (#1694).
7
+
8
+ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
9
+
10
+ **Load when:** modeling a config/policy field, or any onboarding /
11
+ decision / lifecycle state that might be inferred from whether a value
12
+ is present.
13
+
14
+ **⚠️ See also**:
15
+ - [../coding/coding.md](../coding/coding.md) — always-loaded Design
16
+ Principles floor (`**State & Data Modeling (#1695)**`)
17
+ - [../coding/coding.md](../coding/coding.md) — resolver `source`
18
+ provenance (typed | default | default-on-error) for *value*-provenance
19
+
20
+ ## The pattern
21
+
22
+ **In-band signaling** smuggles control or metadata through the data
23
+ channel. **Out-of-band signaling** gives the control signal its own
24
+ field.
25
+
26
+ The cautionary prior art is the blue-box / 2600 Hz tone: phone systems
27
+ shared the control signal with the voice channel, so a tone on the data
28
+ path could seize trunk control. The same footgun appears under several
29
+ names:
30
+
31
+ - Overloaded NULL / sentinel values (SQL NULL meaning "unknown" *and*
32
+ "not applicable" *and* "use default")
33
+ - Connascence of Meaning (Page-Jones) — components silently agreeing
34
+ what a magic value or absence *means*
35
+ - "Make illegal states unrepresentable" — an ambiguous
36
+ "absent-but-decided vs absent-and-undecided" state should not be
37
+ expressible in one field
38
+ - Single Responsibility applied to data — one field, one reason to
39
+ change
40
+
41
+ - ! MUST encode exactly one fact per field
42
+ - ! MUST record decision / onboarding / lifecycle state in an explicit
43
+ out-of-band marker when a workflow needs to know a human chose
44
+ - ⊗ MUST NOT infer decision-state from whether a value field is present
45
+ - ⊗ MUST NOT treat field absence as "incomplete" when omission is a
46
+ deliberate valid default
47
+
48
+ ## The orthogonality test
49
+
50
+ Ask: can fact A and fact B vary independently?
51
+
52
+ | Fact A (value) | Fact B (decided?) | Independent? |
53
+ | --- | --- | --- |
54
+ | value == default | decided = true (accepted default) | yes |
55
+ | value == default | decided = false (never considered) | yes |
56
+ | value == override | decided = true | yes |
57
+ | value == override | decided = false | usually illegal |
58
+
59
+ If two facts can vary independently, they MUST live in separate slots.
60
+ If one fact strictly implies the other, sharing a slot is fine:
61
+
62
+ - **True `Optional<T>`** — absence means "no value" and there is no
63
+ second "was this considered?" question
64
+ - **Tombstones** — a dedicated deleted/absent sentinel that only means
65
+ lifecycle, not a configured value
66
+ - **Value-provenance `source`** — once a resolved value exists, source
67
+ ∈ {typed, default, default-on-error} is a property *of that resolve*,
68
+ not a second independent human decision
69
+
70
+ Worked examples:
71
+
72
+ 1. **WIP cap onboarding (#1694)** — `plan.policy.wipCap` value vs "did
73
+ the operator consider a cap?" Independent; use
74
+ `x-directive/onboarding.wipCapDecided`.
75
+ 2. **Feature flag default** — `enabled: false` may mean "deliberately
76
+ off" or "never configured." If product needs the distinction, store
77
+ an explicit decided marker.
78
+ 3. **Optional timeout** — absence of `timeoutMs` means "use library
79
+ default" and no workflow asks whether a human considered it. One
80
+ fact; one field is fine.
81
+
82
+ ## Three kinds of provenance in directive
83
+
84
+ Directive already separates two of three facts for policy resolution:
85
+
86
+ | Kind | What it answers | Modeled? |
87
+ | --- | --- | --- |
88
+ | **Effective value** | What int/string do we use right now? | yes (the field or default) |
89
+ | **Value-provenance** | Override vs framework default vs error-fallback? | yes (`source` on resolvers / `PolicyField`) |
90
+ | **Decision-provenance** | Did a human choose this (including accepting default)? | **must be modeled out-of-band** |
91
+
92
+ - ! MUST generalize the `source` discipline to decision-provenance:
93
+ never fake "operator decided" from field presence
94
+ - ! MUST leave value fields to mean exactly one thing (e.g.
95
+ `plan.policy.wipCap` = deliberate non-default override only)
96
+ - ~ SHOULD keep decision markers under an `x-directive/` namespaced
97
+ block when the value lives on PROJECT-DEFINITION
98
+
99
+ ## Canonical worked example — wipCap onboarding (#1694)
100
+
101
+ **Before:** `_classify_onboarding` / `classifyOnboarding` treated
102
+ absent `plan.policy.wipCap` as incomplete onboarding. Accepting the
103
+ framework default (omit-by-design, #1186 D1 / #1250) left the field
104
+ absent forever, so the nudge never cleared. Setting a non-default
105
+ cleared the nudge but broke `test_policy_omits_wip_cap`. The nudge was
106
+ structurally unsatisfiable on deft's own repo.
107
+
108
+ **Root cause:** one field carried two orthogonal facts — configured
109
+ value *and* decision-made.
110
+
111
+ **After (#1694 direction 2):**
112
+
113
+ - `plan.policy.wipCap` (or `x-directive/policy.wipCap`) means only a
114
+ deliberate non-default override
115
+ - `plan["x-directive/onboarding"].wipCapDecided` records that the
116
+ operator considered WIP cap (including accepting the default)
117
+ - `writeWipCapDecision` / `writeWipCap` (default path) set the marker
118
+ without materializing the value field
119
+ - `classifyOnboarding` reads decision-provenance, not field presence
120
+
121
+ Greenfield consumers still get prompted until they run
122
+ `deft triage:welcome --onboard` (or otherwise record the decision).
123
+ Deft's own repo commits the marker with `acceptedDefault: true` and
124
+ stays omit-by-design green.
package/scm/github.md CHANGED
@@ -290,6 +290,53 @@ Rationale: `docs/analysis/2026-07-02-agents-md-incident-rule-rationale.md` § SC
290
290
 
291
291
  See also § ghx cache proxy (#884) for install surfaces and read-only vs mutation rules.
292
292
 
293
+ ## Mismatched/headless SCM readiness (#2275)
294
+
295
+ Follow-up to adoption epic #2203 (Decision 7). Framework-local gates
296
+ (`session:start`, `verify:*`, `xbrief:preflight`, `doctor`, `scope:*`,
297
+ local `cache-fresh` checks) run with zero SCM tooling. SCM-dependent gates
298
+ need `gh`/`ghx` **in the execution env** (not only on the install host) plus
299
+ auth.
300
+
301
+ ### Probe contract
302
+
303
+ - ! `session:start` (read-only, cold, and re-arm) reports SCM readiness via
304
+ `[deft scm]` lines and a `scm` object in `--json`. Shallow by default
305
+ (PATH + token presence + short `gh auth status`); deep API validation when
306
+ `--with-network` / `DEFT_SESSION_START_NETWORK=1`.
307
+ - ! `deft scm:status` (alias `scm:readiness`) is the explicit probe verb:
308
+ exit `0` ready / `1` not ready / `2` config. Flags: `--json`,
309
+ `--deep` / `--shallow` / `--depth shallow|deep`.
310
+ - ! When not ready, diagnostics MUST name the reason
311
+ (`binary-absent` | `missing-token` | `unauthenticated` | ...) and list
312
+ skipped gates (`triage:queue`, `issue:ingest`, `pr:*`, `reconcile:issues`,
313
+ `cache:fetch-all`, `scm:*`, ...). Never fail opaquely on a missing binary.
314
+ - ! Session-start itself MUST NOT hard-block when SCM is unavailable
315
+ (framework-local orientation still succeeds).
316
+ - ! SCM-dependent verbs that actually need the network MUST fail loud with
317
+ the #2275 diagnostic (exit non-zero / `ScmStubError`) rather than hang on
318
+ auth prompts or emit an unhelpful spawn error.
319
+ - ⊗ Echo `GH_TOKEN` / `GITHUB_TOKEN` / `GH_ENTERPRISE_TOKEN` values into
320
+ prompts, transcripts, logs, or `--json` payloads -- report presence only
321
+ (`injected_token_present`).
322
+
323
+ ### Making SCM gates runnable in a mismatched env
324
+
325
+ 1. **Host-gh (local / unsandboxed):** install GitHub CLI (or `task setup:ghx`)
326
+ in the *execution* environment, then `gh auth login`. Host credential
327
+ stores are not shared into agent sandboxes.
328
+ 2. **Injected-token (cloud / headless):** set `GH_TOKEN`, `GITHUB_TOKEN`, or
329
+ `GH_ENTERPRISE_TOKEN` in the execution env via host secrets. Runtime mode
330
+ `cloud-headless` infers `github_auth_mode=injected-token` (#1557).
331
+ 3. **Run SCM elsewhere:** keep framework-local work in the sandbox; run
332
+ `triage:*` / `pr:*` / `issue:ingest` from a matched authenticated shell.
333
+ 4. **Deep check:** `deft scm:status --deep` or
334
+ `deft github-auth-modes --json` validates API reachability and optional
335
+ repo access.
336
+
337
+ Contract file: `content/contracts/scm-readiness.md`. Implementation:
338
+ `packages/core/src/scm/readiness.ts`.
339
+
293
340
  ## Windows / ASCII Conventions for Machine-Editable Sections
294
341
 
295
342
  Agent `edit_files` operations can fail when structured file sections contain Unicode characters that do not round-trip cleanly through Windows toolchains (xref warpdotdev/warp#9022). The following rules apply to **machine-editable structured sections**: ROADMAP.md phase bodies, CHANGELOG.md entries, and Open Issues Index rows.
@@ -27,6 +27,42 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
27
27
 
28
28
  ## Ordered-plan / cohort exhaustion (#2402)
29
29
 
30
+ ## Multi-scope turn/cache budget (epic #3009)
31
+
32
+ Multi-scope greenfield (app-bank pins, N story scopes) multiplies agent turns when ceremony, promote, check, and render are re-run per scope. Apply the following after offline seed.
33
+
34
+ ### Offline seed vs implement phase (#3010)
35
+
36
+ ! Distinguish **offline seed** (operator or harness already ran `directive init` / deposit, pin-copied scopes into `xbrief/proposed/`, and recorded session ritual) from the **agent implement phase**.
37
+
38
+ ! When seed + session ritual are already complete for the engagement:
39
+ - ⊗ Run `directive init` again
40
+ - ⊗ Run full cold `session:start` unless hooks deny writes and recovery is required
41
+ - ⊗ Run `directive migrate` or re-copy scopes already present
42
+ - ! Prefer recovery via `session:ready` (or re-arm) when PreToolUse denies — not full re-init
43
+ - ! Documented consumer/harness contract: seed is done once; implement agents only activate+implement
44
+
45
+ ### Batch promote; one active implement (#3011)
46
+
47
+ ! For a multi-scope pin, batch-stage scopes with `task scope:promote -- --batch` (all `proposed/`) or `task scope:promote -- --batch <path>…`.
48
+ ! Implement path remains **one** `scope:activate` + implement at a time — no multi-active write fence.
49
+ ! When pin order is known, do **not** re-list the entire lifecycle tree every scope; walk the known ordered list.
50
+ ⊗ Activate all scopes at once or drop the one-active-scope / story-ready stack.
51
+
52
+ ### Quality check once at end of multi-scope batch (#3012)
53
+
54
+ ! On an approved multi-scope batch (operator-approved multi-story branch, swarm cohort, or pin walk): run full `task check` (merge chokepoint) **once at the end of the batch** (or after the last scope), not after every scope.
55
+ ! Exception: if the last full check **failed**, fix loops MAY re-run check until green.
56
+ ! Pre-PR / merge-ready gates remain end-of-unit — this does not weaken them.
57
+ ! Iteration lane (affected tests / `verify:forward-coverage` / `coverage:hotspots`) still applies **per scope** during implementation (#1704).
58
+ ⊗ Spam full `directive check` / `task check` after every scope when the batch is still mid-flight and the last merge-chokepoint check was green.
59
+
60
+ ### One-shot project:render (#3013)
61
+
62
+ ! Greenfield init seeds a minimal render-ready `PROJECT-DEFINITION`. Treat `task project:render` as a **refresh of items from lifecycle folders**, not multi-turn identity research.
63
+ ⊗ Invent project identity across many turns when seed already stamped the skeleton.
64
+
65
+
30
66
  ! When processing an approved multi-story cohort or an active ordered-plan sequence, stop after the final approved entry. Do not promote or dispatch adjacent stories from queue intuition. Continuation language advances only within the approved order; skill-chaining is non-authorizing.
31
67
 
32
68
  ## Step 0 -- Implementation Preflight (#810)
@@ -39,7 +75,7 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
39
75
  - ! **Swarm-cohort dispatch carve-out**: when this skill is invoked as part of a swarm cohort allocated by `skills/deft-directive-swarm/SKILL.md`, the approved Phase 5 allocation plan satisfies the "explicit operator approval and short rationale recorded in the handoff" requirement above -- the dispatched xBRIEF paths and allocation rationale ARE the consent token. Process each assigned story sequentially under the checkpoint-commit + `task scope:complete` discipline below. Do NOT re-prompt the parent for batching approval mid-cohort -- the all-or-nothing dispatch envelope rule (`AGENTS.md` `## Multi-agent orchestration discipline (#954)`) forbids mid-scope user-approval gates.
40
76
  - ! **Structured consent-token recognition (#1378)**: the canonical recognition path for the carve-out above is the structured `## Allocation context` section of the dispatch envelope (the frozen schema in `templates/agent-prompt-preamble.md`, Story A of #1378). When that section reports `dispatch_kind: swarm-cohort` with a non-null `allocation_plan_id` AND a non-null `batching_rationale`, the consent token is satisfied mechanically -- read `cohort_vbriefs` as the authoritative file boundary and process each entry sequentially under the checkpoint-commit + `task scope:complete` discipline below, without re-prompting the parent for batching approval mid-cohort. When the `## Allocation context` section is ABSENT (pre-#1378 dispatches, solo-interactive sessions), fall back to the #1371 prose carve-out immediately above -- the prose carve-out remains the recognition path of record for un-elevated envelopes.
41
77
  - ! **Within a cohort, between stories**: the working tree MUST be clean after each story's checkpoint commit + `task scope:complete`. If `git status --short` shows uncommitted state between stories (e.g. a missed `task scope:complete` move, an unstaged file from the prior story), checkpoint-commit it and proceed -- do NOT pause to ask the operator. The dirty-tree "ask the operator" branch above applies only at the FIRST story-start of a fresh branch, where uncommitted operator work might legitimately exist.
42
- - ! If the target story is in `xbrief/proposed/`, run `task scope:promote -- <path>` first; if it is in `xbrief/pending/`, run `task scope:activate -- <path>`. After activation, update the path to the active-file location before preflight.
78
+ - ! If the target story is in `xbrief/proposed/`, run `task scope:promote -- <path>` first (or `task scope:promote -- --batch` for a multi-scope pin — #3011); if it is in `xbrief/pending/`, run `task scope:activate -- <path>`. After activation, update the path to the active-file location before preflight.
43
79
  - ! Before any code-writing tool call -- the first scaffold edit, the first `task` invocation that mutates files, or any `start_agent` dispatch that will implement scope -- MUST run `task xbrief:preflight -- <active-story-path>` (the structural intent gate; wraps `scripts/preflight_implementation.py` so the same invocation works whether deft is the project root or installed as a `deft/` subdirectory).
44
80
 
45
81
  The gate exits 0 only when the candidate xBRIEF lives in `xbrief/active/` AND `plan.status == "running"`. Any other state (pending/, proposed/, completed/, active/-with-non-running-status, malformed JSON, missing keys) exits 1 with an actionable redirect to `task xbrief:activate <path>`.
@@ -255,6 +291,9 @@ task test:coverage # >=85% or PROJECT-DEFINITION.xbrief.json override
255
291
  - ! Phase checkpoint commits MAY use the iteration lane; phase is NOT done for PR handoff until full `task check` passes at the merge chokepoint
256
292
  - ⊗ Skip quality gates or claim they passed without running
257
293
  - ⊗ Treat iteration-lane green as merge-ready without full `task check`
294
+ - ! **Multi-scope batch (#3012):** when implementing an approved multi-scope pin/cohort, reserve full `task check` for end-of-batch (or after last scope) unless the last full check failed — then re-run on the fix loop. Do not run full check after every intermediate scope.
295
+ - ⊗ Re-run full install/session ceremony after offline seed when ritual is already complete (#3010) — use `session:ready` for recovery only.
296
+
258
297
 
259
298
  ## Coding Standards (Summary)
260
299
 
@@ -320,6 +359,10 @@ feat(phase-2): add REST API endpoints with integration tests
320
359
  - ⊗ Move to next phase before current passes checks
321
360
  - ⊗ Make commits without running iteration-lane validation; ⊗ skip full `task check` at PR/merge chokepoint (#1704)
322
361
  - ⊗ Proceed without USER.md -- always run the USER.md Gate first
362
+ - ⊗ Re-run `directive init`, cold `session:start`, migrate, or re-copy pin scopes after offline seed when ritual is already complete (#3010)
363
+ - ⊗ Run full `task check` after every intermediate scope of an approved multi-scope batch when the last merge-chokepoint check was green (#3012)
364
+ - ⊗ Promote scopes one-by-one for a known multi-scope pin when `scope:promote --batch` would stage them in one turn (#3011)
365
+
323
366
  - ⊗ Spawn an implementation agent or invoke a code-writing tool against a xBRIEF that has not passed `task xbrief:preflight` (which wraps `scripts/preflight_implementation.py`) -- always run the Step 0 Implementation Preflight (#810) first; satisfy via `task xbrief:activate <path>`
324
367
  - ⊗ Proceed without `COST-ESTIMATE.md` and a recorded build / rescope / no-build / skip(+reason) decision -- always run the Cost Phase Gate (#739) first
325
368
  - ⊗ Proceed with implementation when the build or test toolchain is unavailable -- always run the Toolchain Gate (Step 2) first
@@ -144,7 +144,9 @@ git --no-pager diff master
144
144
  - ! Check for scope creep -- changes that go beyond the spec task acceptance criteria
145
145
  - ! Verify no debug code, TODO comments, or temporary scaffolding remains
146
146
  - ! Confirm no unintended whitespace-only changes or formatting drift
147
- - ! **Run `task pr:check-closing-keywords -- --pr <N>` (or pass `--body-file` / `--commits-file` for offline checking) before opening the PR; refuse to push if findings (#737)**. The lint scans both the PR body AND every commit message for closing-keyword tokens (`close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved`) followed by `#\d+` in negation / quotation / example / code-block contexts. The recurrence record is the Layer 1 / Layer 2 / Layer 3 stack: #167 (post-merge close-verify), #697 / #698 (negation-context substring match), #401 / #700 (persistent `closingIssuesReferences` link), #735 (squash body containing `DOES NOT CLOSE #734` auto-closed #734). When the lint surfaces a known-safe occurrence (e.g. test fixtures that legitimately exercise the trigger token), pass `--allow-known-false-positives <issue-numbers>` to suppress -- DO NOT silently delete the lint invocation
147
+ - ! **Closing-keyword policy (#3015 class D / #737 Layer 0):** Default PR body uses `Tracking: #N` / `Related: #N` / `Refs #N` only. Use `Closes` / `Fixes` / `Resolves #N` only when the **full issue DoD** is met (not Phase A partial / multi-phase mid-stream).
148
+ - ⊗ Write `Closes #N Phase A`, `only if`, `partial`, or other conditional English around a real closing keyword — GitHub ignores the condition and auto-closes (#3015 enterprize#29).
149
+ - ! **Run `task pr:check-closing-keywords` before opening the PR (default mode `both` = FP #737 + intent #3015).** Offline: `--body-file` / `--commits-file`. Scans body and commits for closing-keyword tokens in negation / quotation / example / code-block contexts (FP) and for any unallowlisted real close (intent). When full DoD close is intentional, pass `--allow-close <N,M>` (CLI allowlist only — body trailers are not an authorization path). FP-only: `--mode fp`. Known-safe quoted tokens: `--allow-known-false-positives`. Recurrence stack: #167, #697 / #698, #401 / #700, #735 (class A), #3015 (class D enterprize#29).
148
150
  - ~ Verify the diff tells a coherent story -- a reviewer reading it top-to-bottom should understand the change
149
151
  - ~ If the PR adds or moves any documentation, verify each new doc is reachable from the AGENTS.md reference chain -- an orphan doc is discovered <10% of the time yet still costs context when found (the reference-chain contract, #644 / #647). Add a pointer or fold it in rather than leaving it stranded.
150
152
 
@@ -173,4 +175,4 @@ After exiting:
173
175
  - ⊗ Make out-of-scope fixes during Write -- this introduces scope creep that Diff will flag, forcing another iteration
174
176
  - ⊗ Ignore the iteration count -- more than 3 iterations usually indicates oscillating fixes or an unclear spec task
175
177
  - ⊗ Add a prohibition (`!` or `⊗`) without scanning the same file for conflicting softer-strength rules (`~`, `≉`) that reference the same term
176
- - ⊗ Skip `task pr:check-closing-keywords` (#737) before pushing a PR. The negation-context substring match is the Layer 0 (prevention) gate that prevents the recurring auto-close of umbrella / staying-OPEN issues observed in #697 (closed #642), #401 (closed #642), #700 (closed #233), and #735 (closed #734) -- each incident required manual reopen and downstream cleanup. The lint's three-state exit (0 clean / 1 hits found / 2 config error) MUST be treated as a hard refusal: rewrite the PR body / commit messages until clean, OR pass `--allow-known-false-positives` ONLY for legitimately-quoted occurrences (test fixtures, documentation that discusses the trigger token literally). See `skills/deft-directive-swarm/SKILL.md` Phase 6 Step 1 for the corresponding Layer 3 (recovery) `pr:check-protected-issues` rule (#701)
178
+ - ⊗ Skip `task pr:check-closing-keywords` (#737) before pushing a PR. Intent mode (#3015) also refuses bare/conditional real `Closes #N` without `--allow-close`. The negation-context substring match is the Layer 0 (prevention) gate that prevents the recurring auto-close of umbrella / staying-OPEN issues observed in #697 (closed #642), #401 (closed #642), #700 (closed #233), and #735 (closed #734) -- each incident required manual reopen and downstream cleanup. The lint's three-state exit (0 clean / 1 hits found / 2 config error) MUST be treated as a hard refusal: rewrite the PR body / commit messages until clean, OR pass `--allow-known-false-positives` ONLY for legitimately-quoted occurrences (test fixtures, documentation that discusses the trigger token literally). See `skills/deft-directive-swarm/SKILL.md` Phase 6 Step 1 for the corresponding Layer 3 (recovery) `pr:check-protected-issues` rule (#701)
@@ -55,7 +55,7 @@ On repos with `.deft/core/` installed, **PR shepherding intent** routes here --
55
55
  On OpenClaw hosts with Directive installed (`.deft/core/` or equivalent content deposit), **babysit / shepherd / watch** intent likewise routes here -- not host-local freestyle poll loops and not OpenClaw `cron` alone.
56
56
 
57
57
  - ! When the OpenClaw tool surface exposes `sessions_spawn`, Approach 1 is the **default** babysit path: spawn a background review-monitor via `sessions_spawn` (register with `--platform-primitive sessions_spawn` or the alias `openclaw-sessions-spawn`).
58
- - ! Prefer a **visible** Control UI subagent when OpenClaw Control UI is the operator control plane so humans can inspect the monitor.
58
+ - ! Prefer a **visible** Control UI subagent (`visible:true` when the tool surface allows) when OpenClaw Control UI is the operator control plane so humans can inspect the monitor (#3044; invisible empty settles are higher FC04 residual risk).
59
59
  - ! Long review-monitor ownership (>~3 min) MUST NOT block the parent OpenClaw session — background `sessions_spawn` + parent yield; same Gap D rule as Cursor/Grok Build (#1880).
60
60
  - ! Prefer deep-think gates inside the monitor via the dual-invoke probe order (#2893): `deft pr:watch` / `deft pr:merge-ready` first, then `task deft:pr:watch` when the Taskfile include is present, then the #2878 gh-only fallback — bare `task pr:watch` is not the consumer form.
61
61
  - ⊗ Treat OpenClaw `cron` (or any host scheduler alone) as Approach 1. Cron/timer re-invocation is Approach 2 only when `sessions_spawn` is unavailable.
@@ -362,7 +362,7 @@ Remediation:
362
362
 
363
363
  ! **Heartbeat contract for Cursor pollers (#1877 / #1166 / #2876):** OpenClaw sessions_spawn pollers share this contract. A Cursor `Task` or OpenClaw `sessions_spawn` review-monitor poller whose loop runs > ~3 min MUST honour the sub-agent heartbeat contract (`docs/subagent-heartbeat.md`), same as the `spawn_subagent` path — emit periodic progress so the parent can distinguish a live poller from a hung one.
364
364
 
365
- ~ **Visible Control UI (OpenClaw):** When OpenClaw Control UI is the operator control plane, SHOULD spawn the review-monitor as a **visible** subagent so humans can inspect progress without attaching to the parent session.
365
+ ~ **Visible Control UI (OpenClaw / #3044):** When OpenClaw Control UI is the operator control plane, SHOULD spawn the review-monitor with `visible:true` when the tool surface allows so humans can inspect progress without attaching to the parent session; invisible empty settles are higher FC04 residual risk.
366
366
 
367
367
  ! When the platform descriptor indicates Tier 1 (sub-agent support), spawn a review-monitor sub-agent using the primitive matching the descriptor:
368
368
 
@@ -374,6 +374,51 @@ Remediation:
374
374
 
375
375
  ⊗ Use OpenClaw `cron` alone as Approach 1 when `sessions_spawn` is available — cron is Approach 2 scheduler fallback only (#2876).
376
376
 
377
+ ### Empty announce ≠ done (parent DoD) (#3044 / FC04 residual)
378
+
379
+ ! When a review-monitor settle arrives with **empty body**, **missing `STATUS:` line**, or **status unknown** (including host `(no output)` / empty `subagent_announce`):
380
+
381
+ 1. ! The parent MUST run **same-turn ground truth** before any DONE / CLEAN / merge-ready claim: at least `gh pr view <N>` (or REST `pulls/<N>`), `gh pr checks <N>`, and current HEAD SHA (`gh api repos/<owner>/<repo>/pulls/<N> -q .head.sha`).
382
+ 2. ! Classify the settle as **FC04 residual** (empty babysit ≠ done) until ground truth shows a terminal merge/close outcome **or** an explicit structured `BLOCKED` / `FAILED` handback.
383
+ 3. ⊗ Treat empty / unknown settle as `DONE`, `CLEAN`, merge-ready, or batch-complete.
384
+ 4. ⊗ Spawn a second review-monitor solely because the first settle was empty/unknown without completing the ground-truth batch first (#3044 dual-lease recurrence).
385
+
386
+ ~ Recurrence: enterprize PR #43 (2026-08-02) — first monitor polled live, host settled empty/unknown; parent spawned a second same-`taskName` monitor; dual lease collision while PR stayed open. See also `meta/lessons.md` and FC04 / growth friction R1 + R10.
387
+
388
+ ### Single review-monitor lease (#3044 / #2814)
389
+
390
+ ! **One sticky lease per PR:** ownership is the single sticky GitHub PR comment `<!-- deft:review-owner -->` (or the dual-invoke `review-monitor:register` form that writes it). Parallel ownership is forbidden.
391
+
392
+ ! **Pre-spawn check:** before launching another Approach 1 review-monitor (`sessions_spawn`, `spawn_subagent`, Cursor `Task`, `start_agent`):
393
+
394
+ 1. ! Read the sticky lease (dual-invoke `verify:review-monitor` when available, else `gh api` issues comments for `<!-- deft:review-owner -->`).
395
+ 2. ! List active same-PR / same-`taskName` subagents when the host exposes that surface (OpenClaw `subagents list` or equivalent).
396
+ 3. ⊗ Spawn a second monitor while a prior owner is **running**.
397
+ 4. ⊗ Spawn a second monitor when the last settle was **empty/unknown** and ground truth has **not** shown a terminal merge/close (or explicit structured handback that releases ownership).
398
+ 5. ! If the prior owner is **dead** (liveness fail / `REDISPATCH_OK` / `verify:subagent-alive` exit 1) and the PR is still open: spawn **one** replacement monitor and re-claim the lease with **`--force`** (CLI: `deft review-monitor:register --pr <N> --monitor-agent-id <id> --force` / task: `task review-monitor:register -- --pr <N> --monitor-agent-id <id> --force`, or host equivalent force takeover) so a non-expired foreign lease does not block replacement — then **update** the sticky lease comment to the new owner. Never silent dual ownership.
399
+ 6. ! On register conflict when the prior owner is **still alive**: attach to the existing owner or stop — do not parallel-fix.
400
+ 7. ⊗ Refuse replacement of a dead owner solely because the 30-minute lease has not expired without attempting force takeover (#3044).
401
+
402
+ ### Required non-empty monitor handback (#3044)
403
+
404
+ ! Approach 1 review-monitor prompts (including `templates/swarm-greptile-poller-prompt.md` and any host-filled spawn prompt) MUST require a **non-empty** final handback with these fields:
405
+
406
+ ```text
407
+ STATUS: DONE|BLOCKED|FAILED
408
+ HEAD: <sha>
409
+ CHECKS: <summary>
410
+ MERGE: <url|error|n/a>
411
+ ISSUE: <closed|open|n/a>
412
+ NOTES: <short>
413
+ ```
414
+
415
+ ⊗ Empty final assistant message from a review-monitor.
416
+ ⊗ Parent treating a settle that lacks `STATUS:` as success.
417
+
418
+ ~ **Visible Control UI risk (#3044):** When OpenClaw Control UI is the operator plane, prefer `visible:true` on the review-monitor spawn; invisible empty settles are higher risk for FC04 misclassification. Cross-link: `skills/deft-directive-swarm/references/host-openclaw.md` Babysit / review-monitor residual.
419
+
420
+
421
+
377
422
  **Approach 2 (fallback -- no sub-agent primitive for the descriptor):**
378
423
 
379
424
  ! When the platform descriptor indicates no sub-agent orchestration (or the primitive is unavailable), use discrete tool calls with a yield between checks. For `grok-build` / spawn_subagent descriptor this path is normally avoided in favor of Approach 1; it exists for pure interactive or limited runtimes.
@@ -566,3 +611,6 @@ task lifecycle:event -- emit plan:approved \
566
611
  - ⊗ Activate Approach 3 (blocking `Start-Sleep` loop) without first warning the user that it will lock the conversation pane and receiving confirmation
567
612
  - ⊗ Exit the review loop on a Greptile confidence number alone while the check run is non-terminal -- a confidence score is NOT a verdict without a terminal check-run (`completed` + `{success, neutral}`) AND a HEAD-matching `Last reviewed commit:` completion marker (#1259)
568
613
  - ⊗ Call `gh pr merge` on cached/earlier review state without an immediately-preceding pre-merge re-poll that re-satisfies the Step 6 fail-closed all-of (#1259)
614
+ - ⊗ Treat empty/unknown review-monitor settle as DONE/CLEAN/merge-ready without same-turn ground truth (#3044 / FC04 residual)
615
+ - ⊗ Spawn a second review-monitor while prior owner is running or last settle was empty/unknown without terminal ground truth (#3044)
616
+ - ⊗ Accept empty review-monitor final message missing STATUS/HEAD/CHECKS/MERGE handback (#3044)
@@ -23,6 +23,7 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
23
23
  - User says "set up deft", "configure deft", or "bootstrap my project"
24
24
  - User asks to create USER.md, PROJECT-DEFINITION.xbrief.json, or a specification
25
25
  - User clones a deft-enabled repo for the first time with no config
26
+ - User says "revisit experimental rules", "toggle experimental meta", "enable SOUL", "disable morals", or wants to change Experimental Rules after bootstrap (#46)
26
27
 
27
28
  ## Opt-out flag (`.no-deft-directive`) (#2926)
28
29
 
@@ -194,12 +195,28 @@ VBA (Excel macros), VHDL, Visual Basic (.NET), Zig, 6502-DASM
194
195
  2. ! If `deft_version` is present but **differs from the current framework version** (0.20.0): check whether any expected fields are missing from the USER.md
195
196
  3. ! If fields are missing: query the user for each missing field individually -- do NOT re-run the full Phase 1 interview
196
197
  4. ! After completing any field queries (even if none were needed), write the current `deft_version` (0.20.0) to USER.md
197
- 5. ~ If `deft_version` matches the current version and all expected fields are present: no action needed (USER.md is fresh)
198
+ 5. ~ If `deft_version` matches the current version and all expected fields are present: USER.md is fresh — do **not** re-run Phase 1. ! Still offer the **Returning-user re-entry** menu below so the operator can revisit Experimental Rules or continue to Phase 2 without a full re-interview (#46).
198
199
 
199
200
  Expected USER.md fields: **Name**, **Custom Rules**, **Default Strategy**, and optionally **Coverage** and **Experimental Rules**.
200
201
 
201
202
  ⊗ Re-run the full Phase 1 interview when only individual fields are missing from a stale USER.md -- query missing fields individually instead.
202
203
 
204
+ ### Returning-user re-entry (#46)
205
+
206
+ ! When USER.md already exists (fresh or after individual missing-field fill), present a deterministic numbered menu before assuming Phase 1 is "done and silent":
207
+
208
+ > "USER.md is in place. What next?"
209
+ > 1. Continue to Phase 2 (project configuration) ★ (recommended when project config is still missing)
210
+ > 2. **Revisit experimental rules** — enable/disable SOUL / morals / code-field without hand-editing schema
211
+ > 3. Not now (exit setup)
212
+ > 4. Discuss
213
+ > 5. Back
214
+
215
+ - ! Final two numbered options MUST be `Discuss` and `Back` per [`../../contracts/deterministic-questions.md`](../../contracts/deterministic-questions.md)
216
+ - ! On option 2, enter **Revisit experimental rules** (next section) — not a full Phase 1 re-interview
217
+ - ⊗ Silently skip past a complete USER.md with no re-entry offer when the operator entered setup (or asked to configure preferences)
218
+ - ⊗ Invent a `deft config` / `task config:*` verb family for this slice — setup skill re-entry is the product surface (#46)
219
+
203
220
  ### Interview Rules
204
221
 
205
222
  ! This phase follows the deterministic interview loop defined in `skills/deft-directive-interview/SKILL.md`. The core rules (one question per turn, numbered options with stated default, explicit "other" escape, depth gate, default acceptance, confirmation gate, structured handoff) apply here. Key points repeated for emphasis:
@@ -307,6 +324,89 @@ for project-scoped settings (strategy, coverage).
307
324
 
308
325
  ---
309
326
 
327
+ ## Revisit experimental rules (#46)
328
+
329
+ **Goal:** Guided enable/disable of USER.md **Experimental Rules** entries that *reference* framework deposit meta files (`meta/SOUL.md`, `meta/morals.md`, `meta/code-field.md`). This is a post-bootstrap return path — not Phase 1 bootstrap, not a general preferences UI, and not an editor for framework meta file bodies.
330
+
331
+ ### When to enter
332
+
333
+ - Returning-user re-entry option **Revisit experimental rules**
334
+ - Direct user ask: "revisit experimental rules", "toggle experimental meta", "turn on SOUL", "disable code-field", etc.
335
+ - USER.md exists and is complete enough to edit (Name present); missing non-meta fields still use Freshness Detection individual queries first
336
+
337
+ ### Out of scope
338
+
339
+ - ⊗ General preferences UI / rewriting Personal or Defaults sections as part of this path
340
+ - ⊗ Editing framework `meta/*.md` content (deposit owns SOUL / morals / code-field bodies; `directive update` refreshes deposit)
341
+ - ⊗ Deposit layout changes
342
+ - ⊗ Inventing a full `deft config` mega-surface or new `task config:*` verb family for this slice
343
+ - ⊗ Re-building USER.md bootstrap / non-overwrite semantics
344
+ - ⊗ Treating Experimental Rules lines as project-local copies of meta files — they are **references** only
345
+
346
+ ### Flow
347
+
348
+ ! **Each message MUST contain exactly ONE question** (same interview rule as Phase 1).
349
+
350
+ 1. ! Resolve USER.md via Platform Detection (`$DEFT_USER_PATH` → platform path). Read the file as **UTF-8**.
351
+ 2. ! Parse current Experimental Rules state (on/off) for the three paths:
352
+ - `meta/SOUL.md`
353
+ - `meta/morals.md`
354
+ - `meta/code-field.md`
355
+ - Detection: any line containing that path counts as **on** (custom wording still counts).
356
+ 3. ! Show a **current state** summary (table or short list), for example:
357
+
358
+ | Entry | State | Role |
359
+ |-------|-------|------|
360
+ | SOUL.md | on/off | Results-first agent persona |
361
+ | morals.md | on/off | Epistemic honesty |
362
+ | code-field.md | on/off | Pre-code assumption protocol |
363
+
364
+ 4. ! Ask which entry to change with a deterministic numbered menu (one question). Options MUST include each of the three entries as toggle targets, plus **Done (save)** / **Done (discard)**, and final two options `Discuss` and `Back`:
365
+
366
+ > "Toggle which experimental meta entry? (current state shown above)"
367
+ > 1. SOUL.md — currently {on|off}
368
+ > 2. morals.md — currently {on|off}
369
+ > 3. code-field.md — currently {on|off}
370
+ > 4. Done — save changes
371
+ > 5. Done — discard changes
372
+ > 6. Discuss
373
+ > 7. Back
374
+
375
+ 5. ! When the user picks an entry (1–3), optionally show the short Phase 1 explainer (steps **5a–5c** copy below), then confirm the new on/off value with a Y/n or numbered keep/flip menu. Update the **in-memory** desired state; do not write yet. Return to the toggle menu (step 4) until Done.
376
+ 6. ! On **Done — save**: show a confirmation summary of the three final on/off values and require explicit affirmative (`yes` / `confirmed` / `approve`) before write — same Post-Interview Confirmation Gate strictness.
377
+ 7. ! On **Done — discard** or **Back** without save: leave USER.md unchanged and return to the Returning-user re-entry menu (or exit if invoked directly).
378
+
379
+ ### Explainers (reuse Phase 1 steps 5a–5c)
380
+
381
+ - **SOUL.md** — Results-first agent persona (inspired by Winston Wolf). Enforces assess-before-acting, finish-what-you-start, right-tool-for-the-job, and play-the-long-game. Keeps the AI decisive and concise. Includes a named persona ('Vinston') — drop if you prefer to define your own agent personality.
382
+ - **morals.md** — Epistemic honesty rules. No presenting speculation as fact, label unverified claims, self-correct when wrong. Foundational trust rules for any AI agent. Strongly recommended.
383
+ - **code-field.md** — Pre-code assumption protocol. Requires stating assumptions and naming failure modes before writing a single line. Fights the 'it compiles, ship it' instinct. Based on NeoVertex1 context-field.
384
+
385
+ ### Safe write rules (non-clobber)
386
+
387
+ ! When persisting toggles to USER.md:
388
+
389
+ 1. ! Write **UTF-8** (no BOM). Create parent directories only if the resolved path's parent is missing — never relocate USER.md.
390
+ 2. ! Change **only** the `## Experimental Rules` section (add the section if enabling when absent; remove the section when all three are off and no custom bullets remain).
391
+ 3. ! Canonical enable lines (match Phase 1 template):
392
+ - `- ! Use meta/SOUL.md for strategic context and purpose-driven guidance`
393
+ - `- ! Use meta/morals.md for ethical AI development principles`
394
+ - `- ~ Use meta/code-field.md for advanced architecture patterns`
395
+ 4. ! Disable = remove lines that mention that path. Preserve any **custom** non-meta bullets under Experimental Rules.
396
+ 5. ! **Personal** and **Defaults** section bodies MUST remain byte-identical to the pre-write file (non-clobber).
397
+ 6. ~ Prefer the pure helper `applyExperimentalRulesState` / `setExperimentalRule` from `@deftai/directive-core` `userConfig` (`packages/core/src/user-config/experimental-rules.ts`) when the package is importable (framework checkout, tests, or a thin local script). When editing by hand as an agent, apply the same rules: section-only edit, UTF-8, path-based match, canonical enable lines.
398
+ 7. ! After write, re-read USER.md and show the final on/off state to the user.
399
+
400
+ ⊗ Rewrite the whole USER.md from the Phase 1 template when only Experimental Rules changed
401
+ ⊗ Clobber or reformat **Personal** / **Defaults** content while toggling experimental meta
402
+ ⊗ Hand-edit framework `meta/SOUL.md`, `meta/morals.md`, or `meta/code-field.md` bodies as part of this path
403
+ ⊗ Invent `deft config` / `task config:experimental-*` for this product slice when setup re-entry suffices
404
+
405
+ ### Then
406
+
407
+ - ! After a successful save (or discard), re-offer the Returning-user re-entry menu (Continue to Phase 2 / Revisit again / Exit / Discuss / Back) unless the user asked only for the toggle and is done.
408
+ - ~ If Phase 2 is already complete, prefer Exit over Continue unless the user wants project reconfiguration.
409
+
310
410
  ## Phase 2 — Project Configuration (PROJECT-DEFINITION.xbrief.json)
311
411
 
312
412
  **Goal:** Project-specific configuration — tech stack, type, quality standards — written as a xBRIEF file at `./xbrief/PROJECT-DEFINITION.xbrief.json`.
@@ -741,3 +841,6 @@ Per [strategies/interview.md](../../strategies/interview.md#interview-rules-shar
741
841
  - ⊗ Present choices through a host UI that replaces the canonical numbers with alphabetic affordances or unlabeled buttons
742
842
  - ⊗ Resolve paths relative to the skill file, AGENTS.md, or framework directory instead of the user's pwd at skill entry
743
843
  - ⊗ Generate an authoritative PRD.md — PRD.md is a read-only export via `task prd:render`, never a source of truth
844
+ - ⊗ Skip the Returning-user re-entry / Revisit experimental rules path when USER.md exists and the operator entered setup to change experimental meta (#46)
845
+ - ⊗ Clobber Personal or Defaults while toggling Experimental Rules (#46)
846
+ - ⊗ Invent a full `deft config` verb family for experimental meta when setup re-entry suffices (#46)
@@ -92,6 +92,7 @@ CONSTRAINTS:
92
92
 
93
93
  ## Anti-Patterns
94
94
 
95
+ - ⊗ Parent conversation implements or babysits product fix/CI loops for **through merge** / **drive-to: merge-ready** story work when background subagent/worktree dispatch is available — even if cohort size is 1; use the swarm/solo-worker launch path (#3032 / #1880 Gap C)
95
96
  - ⊗ Start prompts with context or description instead of an imperative TASK directive
96
97
  - ⊗ Use `--mcp` with Warp MCP server UUIDs from standalone (non-Warp) terminals
97
98
  - ⊗ Assign overlapping files to multiple agents
@@ -4,6 +4,12 @@
4
4
 
5
5
  ! Before assigning work to agents, build the cohort from the triage queue (queue-driven per #1142 / N2; see Step 0 below), then read project state and plan allocation against the activated cohort.
6
6
 
7
+ ### Through-merge / N=1 still uses the launch path (#3032)
8
+
9
+ ! When operator intent is **through merge**, **drive to merge**, **land/ship issue**, or explicit **drive-to: merge-ready** for story work, the parent (monitor) conversation MUST NOT implement product code or own the implementation PR as the leaf. Parent MUST run this skill's launch path: worktree isolation when available, worker envelope with `drive-to: merge-ready`, xBRIEF preflight, pre-pr + review-cycle, then merge/`scope:complete` per #1880 Gap C.
10
+ ! **Cohort size N=1 is still a cohort for dispatch.** Solo through-merge uses the same swarm/solo-worker launch path as multi-story (`dispatch_kind: solo` or a one-story swarm-cohort). Do not treat "only one issue" as permission for the parent to code.
11
+ ⊗ Parent implements, babysits product fix loops, or skips worktree + worker dispatch for through-merge / drive-to:merge-ready work when background subagent/worktree dispatch is available (#3032).
12
+
7
13
  ### Headless cohort fast-path: low-ceremony launch (C1 / #1387)
8
14
 
9
15
  ! When the operator supplies a **pre-approved cohort** via the **C1** `task swarm:launch` CLI, Phase 0 runs in headless / low-ceremony mode: the per-phase interactive approval gates (the Step 0c promote-fill prompts, the Step 0.5 lifecycle-bridge approval, and the Step 4/5 allocation approval) collapse into a SINGLE consent -- the `## Allocation context` token (#1378) carried in the dispatch envelope. The interactive promote-fill loop (Step 0a -- 0d below) is SKIPPED.
@@ -73,6 +73,16 @@ Package install alone does not put always-pins into `~/.openclaw/workspace/skill
73
73
  ! Babysit / PR shepherd on OpenClaw remains **Approach 1** via `sessions_spawn` (`skills/deft-directive-review-cycle/SKILL.md`). Cron alone is not Approach 1 (#2874 / #2876).
74
74
  ⊗ Regress babysit to main-session `gh` poll + cron when `sessions_spawn` is available.
75
75
 
76
+ ### Empty announce ≠ done + single lease residual (#3044)
77
+
78
+ Skill residual of #2874 / #2876 (spawn routing fixed; post-spawn ownership still thrashed). Canonical MUST language lives in `skills/deft-directive-review-cycle/SKILL.md` (`### Empty announce ≠ done`, `### Single review-monitor lease`, `### Required non-empty monitor handback`).
79
+
80
+ ! On empty body / missing `STATUS:` / status-unknown review-monitor settle (`subagent_announce` with `(no output)` included): parent MUST same-turn ground truth (`gh pr view` + `gh pr checks` + HEAD) and MUST NOT treat the settle as DONE/CLEAN/merge-ready — **FC04 residual**.
81
+ ! One sticky `<!-- deft:review-owner -->` lease per PR. Pre-spawn: list active same-`taskName` / lease holder. ⊗ Second monitor while prior owner is running **or** last settle was empty/unknown without terminal ground truth. Dead owner + open PR → one replacement + lease update only.
82
+ ! Monitor handback MUST be non-empty with `STATUS` / `HEAD` / `CHECKS` / `MERGE` (see review-cycle skill + `templates/swarm-greptile-poller-prompt.md`).
83
+ ~ Prefer `visible:true` when Control UI is the operator plane; invisible empty settles raise FC04 misclassification risk.
84
+ ~ Recurrence: enterprize PR #43 (2026-08-02) dual-monitor + empty settle.
85
+
76
86
  ## Monitor / completion channel
77
87
 
78
88
  ! Completion is parent push / announce. Do not poll via Grok Build `get_command_or_subagent_output` or Cursor Task-complete semantics.
package/tasks/pr.yml CHANGED
@@ -28,18 +28,17 @@ tasks:
28
28
  vars:
29
29
  ENGINE_CMD: 'pr-protected-issues {{.CLI_ARGS}}'
30
30
 
31
- # pr:check-closing-keywords -- Layer 0 (prevention) closing-keyword
32
- # negation-context lint introduced by #737. Refuses to push when the
33
- # PR body or any commit message contains a closing-keyword token in a
34
- # negation / quotation / example / code-block context. Pairs with the
35
- # existing Layer 3 (recovery) ``pr:check-protected-issues`` (#701).
31
+ # pr:check-closing-keywords -- Layer 0 prevention (#737 FP + #3015 intent).
32
+ # Default --mode both: FP (negation/quote/example/code) + intent (any real
33
+ # Closes/Fixes/Resolves #N unless --allow-close N,M). Body trailers are not
34
+ # an authorization path. Pairs with Layer 3 ``pr:check-protected-issues`` (#701).
36
35
  #
37
36
  # Per ``conventions/task-caching.md`` (#574): NO ``sources:`` /
38
37
  # ``generates:`` because user-facing recovery flags (``--pr``,
39
- # ``--body-file``, ``--commits-file``, ``--allow-known-false-positives``)
40
- # MUST NOT be silently swallowed by go-task's incremental-build cache.
38
+ # ``--body-file``, ``--commits-file``, ``--allow-known-false-positives``,
39
+ # ``--allow-close``, ``--mode``) MUST NOT be silently swallowed by go-task cache.
41
40
  check-closing-keywords:
42
- desc: "Scan PR body + commit messages for closing-keyword substrings in negation/quotation/example contexts that would trigger Layer 0 false-positive auto-closes (#737)"
41
+ desc: "Scan PR body + commits for closing-keyword FP contexts (#737) and unallowlisted real closes / intent mode (#3015 class D). Default --mode both."
43
42
  dir: '{{.USER_WORKING_DIR}}'
44
43
  deps: [":engine:_ts-build"]
45
44
  env:
package/tasks/roadmap.yml CHANGED
@@ -12,7 +12,7 @@ vars:
12
12
 
13
13
  tasks:
14
14
  render:
15
- desc: Render ROADMAP.md from pending/ and completed/ lifecycle folders
15
+ desc: Render ROADMAP.md from pending/ proposed/ active/ (forward) and capped completed/
16
16
  dir: '{{.USER_WORKING_DIR}}'
17
17
  deps:
18
18
  - task: :engine:_ts-build
package/tasks/scope.yml CHANGED
@@ -36,7 +36,10 @@ vars:
36
36
  tasks:
37
37
 
38
38
  promote:
39
- desc: "Promote a vBRIEF scope: proposed/ -> pending/ (status: pending)"
39
+ # Single: task scope:promote -- xbrief/proposed/<file>.xbrief.json
40
+ # Batch (#3011): task scope:promote -- --batch (all proposed/)
41
+ # task scope:promote -- --batch path1 path2 [--force]
42
+ desc: "Promote a vBRIEF scope: proposed/ -> pending/ (status: pending). Batch: --batch [paths...] (#3011)."
40
43
  dir: '{{.USER_WORKING_DIR}}'
41
44
  deps:
42
45
  - task: :engine:_ts-build
package/tasks/spec.yml CHANGED
@@ -23,14 +23,17 @@ tasks:
23
23
  ENGINE_CMD: 'spec-validate --project-root "{{.USER_WORKING_DIR}}"'
24
24
 
25
25
  render:
26
- desc: Render the specification artifact to SPECIFICATION.md
26
+ desc: >-
27
+ Render the specification artifact to a compact SPECIFICATION.md by default
28
+ (#1566: no completed lifecycle dump, no LegacyArtifacts). Opt in via
29
+ --include-scopes=current|all and --include-legacy-artifacts=on after --.
27
30
  dir: '{{.USER_WORKING_DIR}}'
28
31
  deps:
29
32
  - task: :engine:_ts-build
30
33
  cmds:
31
34
  - task: :engine:invoke
32
35
  vars:
33
- ENGINE_CMD: 'spec-render --project-root "{{.USER_WORKING_DIR}}"'
36
+ ENGINE_CMD: 'spec-render --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
34
37
 
35
38
  pipeline:
36
39
  desc: Run full spec pipeline (validate then render)