@deftai/directive-content 0.110.0 → 0.112.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/QUICK-START.md +16 -14
- package/SKILL.md +13 -13
- package/Taskfile.yml +20 -15
- package/UPGRADING.md +64 -24
- package/commands.md +20 -18
- package/contracts/design-critique.md +36 -13
- package/conventions/machine-generated-banner.md +9 -9
- package/conventions/rule-ownership.json +3 -3
- package/docs/SUPPORT.md +43 -0
- package/docs/capabilities.md +110 -0
- package/docs/capability-overlay.json +197 -0
- package/docs/getting-started.md +131 -49
- package/docs/scope-provenance.md +2 -0
- package/main.md +22 -22
- package/package.json +1 -1
- package/packs/rules/rules-pack-0.1.json +1 -1
- package/packs/skills/skills-pack-0.1.json +9 -7
- package/scm/github.md +2 -0
- package/skills/deft-directive-design-critique/SKILL.md +10 -4
- package/skills/deft-directive-release/SKILL.md +22 -17
- package/skills/deft-directive-review-cycle/SKILL.md +52 -15
- package/skills/deft-directive-swarm/SKILL.md +8 -4
- package/skills/deft-directive-swarm/references/core-ops.md +1 -0
- package/skills/deft-directive-swarm/references/core-phase-0.md +2 -1
- package/skills/deft-directive-swarm/references/core-phase-3.md +8 -5
- package/skills/deft-directive-swarm/references/host-claude-code.md +3 -2
- package/skills/deft-directive-swarm/references/host-grok-build.md +19 -3
- package/skills/deft-directive-swarm/references/host-grokbot.md +151 -0
- package/tasks/docs.yml +19 -0
- package/tasks/migrate.yml +3 -1
- package/tasks/policy.yml +2 -2
- package/tasks/scm.yml +12 -1
- package/tasks/scope.yml +16 -25
- package/tasks/triage-actions.yml +3 -4
- package/tasks/triage-bootstrap.yml +2 -2
- package/tasks/triage-bulk.yml +6 -7
- package/tasks/triage-classify.yml +2 -2
- package/tasks/triage-queue.yml +2 -2
- package/tasks/triage-reconcile.yml +2 -2
- package/tasks/triage-scope-drift.yml +2 -2
- package/tasks/triage-scope.yml +2 -2
- package/tasks/triage-smoketest.yml +3 -3
- package/tasks/triage-subscribe.yml +2 -2
- package/tasks/triage-summary.yml +2 -2
- package/tasks/triage-welcome.yml +2 -2
- package/tasks/verify.yml +30 -1
- package/templates/PULL_REQUEST_TEMPLATE.md +12 -0
- package/templates/agent-prompt-preamble.md +6 -3
- package/templates/agents-entry.md +5 -5
- package/templates/design-critique-brief.md +2 -0
package/QUICK-START.md
CHANGED
|
@@ -52,17 +52,20 @@ Run these deterministic checks, in order:
|
|
|
52
52
|
|
|
53
53
|
### 1b. Does `../AGENTS.md`'s managed section match the current template? Do referenced paths resolve?
|
|
54
54
|
|
|
55
|
+
Do **not** parse managed-section markers, byte-compare an attributed block against the template, or locate a hardcoded v2 managed-section marker. Detection is the four-state classifier (`current | stale | missing | absent`) from `deft agents:refresh --check` — the same plan `deft doctor` uses. v1/v2 markers are force-stale. Truncated or future markers are unreadable (do not append).
|
|
56
|
+
|
|
55
57
|
Three checks here, in this order. The first match wins; later checks only run when earlier checks pass.
|
|
56
58
|
|
|
57
|
-
1. **
|
|
58
|
-
- ! If
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
1. **Classifier (Case G gate).** Run `deft agents:refresh --check` (or `deft doctor`). If the CLI is not on PATH, run `npx @deftai/directive agents:refresh --check` or `npm i -g @deftai/directive` then the same verb. If the payload is missing, run `deft update`. Pre-canonical layout: frozen Go bridge (see UPGRADING.md / GitHub releases).
|
|
60
|
+
- ! If state is **stale**, **missing**, **absent**, or **unreadable**, treat as **stale content** -- jump to Case G ("Stale AGENTS.md") in Step 2. Case G remediates with the registered rewrite, not a hand-append.
|
|
61
|
+
- If state is **current**, continue to the install-path check below.
|
|
62
|
+
2. **Install-path resolution (Case K gate -- #1046 PR-A).** When the classifier reports **current**, parse the section for its install-path declaration (`Full guidelines: <root>/main.md`, e.g. `.deft/core/main.md` for the canonical install layout or `deft/main.md` for the legacy install layout). Verify that `../<root>/main.md` exists on disk.
|
|
63
|
+
- ! If the classifier reports **current** BUT the declared install path does NOT resolve, jump to **Case K ("Install location mismatch")** in Step 2. Refreshing the managed section is a documented no-op when the content already matches -- Case K is a different failure class than Case G and demands a different remediation (#1046 finding #2).
|
|
61
64
|
3. **Legacy skill-path resolution (v0.19 AGENTS.md backstop).** Parse `../AGENTS.md` for any token matching `deft/skills/<name>/SKILL.md` (the legacy v0.19 path shape) and verify the file exists under `./skills/<name>/SKILL.md` (relative to this QUICK-START.md).
|
|
62
65
|
- ! If any referenced path does not exist on disk, treat `../AGENTS.md` as **stale** -- jump to Case G in Step 2.
|
|
63
66
|
- If all referenced paths exist, continue to 1c.
|
|
64
67
|
|
|
65
|
-
Priority ordering: Case G (
|
|
68
|
+
Priority ordering: Case G (classifier not current) always wins over Case K (install-path mismatch) because the registered refresh is the higher-priority remediation -- when the template content has moved on, the refresh closes BOTH the content drift and any incidental install-path mismatch that the new content might re-introduce. Case K only fires when the classifier is current AND the path is unresolved -- the exact "refresh would be a no-op" failure class issue #1046 documents.
|
|
66
69
|
|
|
67
70
|
**Big-jump joint check (Case G+H gate).** Before acting on ANY Case G routing above (a byte-different managed section, or an unresolved legacy skill path), first ALSO evaluate the 1c pre-cutover check below against `../`. ! If 1c ALSO holds (real pre-v0.20 `SPECIFICATION.md` / `PROJECT.md` present), the project is in the **joint big-jump state** where both the AGENTS.md refresh (Case G) and the pre-cutover migration (Case H) are due — jump to **Case G+H** (combined single-session remediation) in Step 2 instead of Case G. The combined path runs the refresh and the migration in one session and emits a single restart, avoiding the wasted Case G → restart → Case H round-trip. If 1c does not hold, route to Case G as usual.
|
|
68
71
|
|
|
@@ -91,16 +94,15 @@ Pick exactly one case from Step 1 and follow its instructions. Do not mix cases.
|
|
|
91
94
|
|
|
92
95
|
### Case F — No AGENTS.md (fresh install)
|
|
93
96
|
|
|
94
|
-
1.
|
|
95
|
-
2.
|
|
96
|
-
3.
|
|
97
|
-
4. Continue to Step 3.
|
|
97
|
+
1. ! Run `deft agents:refresh` (the registered rewrite for classifier state `absent`). ⊗ Do not copy `templates/agents-entry.md` by hand. If the CLI is not on PATH: `npx @deftai/directive agents:refresh` or `npm i -g @deftai/directive`, then the same verb. Payload missing: `deft update`. Pre-canonical layout: frozen Go bridge (UPGRADING.md / GitHub releases).
|
|
98
|
+
2. Tell the user: "✓ Created AGENTS.md at your project root."
|
|
99
|
+
3. Continue to Step 3.
|
|
98
100
|
|
|
99
101
|
### Case G — Stale AGENTS.md (v0.19 → v0.20 upgrade)
|
|
100
102
|
|
|
101
|
-
1.
|
|
102
|
-
2.
|
|
103
|
-
3. If the `
|
|
103
|
+
1. ⊗ Do not locate the `deft/main.md` sentinel, do not append `templates/agents-entry.md`, and do not hand-rewrite markers. QUICK-START is not a second parser.
|
|
104
|
+
2. ! Run `deft agents:refresh`. That command is the four-state plan (`current | stale | missing | absent`; v1/v2 force-stale). Truncated close refuses to write a second section.
|
|
105
|
+
3. If the CLI is not on PATH: `npx @deftai/directive agents:refresh` or `npm i -g @deftai/directive`, then the same verb. Payload missing or drifted: `deft update`. Pre-canonical layout: frozen Go bridge (UPGRADING.md / GitHub releases).
|
|
104
106
|
4. Tell the user: "✓ Refreshed Deft-managed section of AGENTS.md. Your existing additions outside that region were preserved."
|
|
105
107
|
5. ! Instruct the user: **"Framework updated. Start a new agent session to pick up the changes. The current session has stale context."** Do not continue past this instruction in the current session.
|
|
106
108
|
|
|
@@ -118,7 +120,7 @@ Reached only via the **Big-jump joint check** in 1b: the managed section in `../
|
|
|
118
120
|
|
|
119
121
|
! Run the two remediations in this exact order — **AGENTS.md refresh first, frozen migration guidance second** — then emit a **single** restart instruction at the very end:
|
|
120
122
|
|
|
121
|
-
1. **Refresh AGENTS.md first (Case G work).** Perform Case G steps 1-4
|
|
123
|
+
1. **Refresh AGENTS.md first (Case G work).** Perform Case G steps 1-4: run `deft agents:refresh` (registered rewrite). ⊗ Do not append. ⊗ Do NOT emit the Case G step-5 restart instruction here — the combined path defers the single restart to step 3.
|
|
122
124
|
2. **Surface frozen migration path second (Case H work).** Perform Case H steps 1-3 verbatim: explain the v0.59.0 pinned migrator path (#2068), run `task migrate:preflight`, and point at UPGRADING.md. The operator (or a machine with v0.59.0 deposited) runs `task migrate:vbrief` outside the current npm deposit. ⊗ Do NOT perform Case H steps 4-5 until migration has completed on the pinned release and the operator has upgraded to current npm.
|
|
123
125
|
3. **Single restart, exactly once.** Only after BOTH the refresh and the operator-confirmed migration + npm upgrade have completed, ! instruct the user EXACTLY ONCE: **"Framework updated and project migrated. Start a new agent session to pick up the changes. The current session has stale context."** ⊗ Do NOT emit a second restart instruction.
|
|
124
126
|
|
|
@@ -140,7 +142,7 @@ For the version-by-version context of a big jump, see the [big-jump triage entry
|
|
|
140
142
|
The managed section in `../AGENTS.md` is byte-identical to the current `./templates/agents-entry.md` render, BUT the install path the managed section declares (e.g. `.deft/core/main.md`) does NOT resolve on disk. This is the failure class issue #1046 finding #2 documents: Case G's "refresh the managed section" prescription is a byte-for-byte no-op against the current template, so re-running just re-detects the same staleness next session.
|
|
141
143
|
|
|
142
144
|
1. Tell the user (verbatim phrasing, naming the unresolved path): "AGENTS.md's managed section is byte-identical to the current template, but the install path it declares (`<declared-path>`) does NOT exist on disk. Refreshing the managed section would be a no-op -- Case G's remediation does not fix install-location mismatches."
|
|
143
|
-
2. ! Direct the user to run `
|
|
145
|
+
2. ! Direct the user to run `deft doctor` (the diagnostic + remediation surface that owns Case K's fix path) OR to manually verify that the install path AGENTS.md claims actually exists on disk. Confirm the framework is deposited at the path AGENTS.md declares, OR run `deft update` / `npx @deftai/directive update` to deposit at that path, OR hand-edit AGENTS.md to point at the path where the framework actually lives. Pre-canonical layout: frozen Go bridge (UPGRADING.md / GitHub releases).
|
|
144
146
|
3. ⊗ Run a Case G refresh -- it is a documented no-op for Case K. The managed section already byte-matches the current template; refreshing the bytes back to the same bytes does not change which install path is declared.
|
|
145
147
|
4. ! Instruct the user: **"Stop here. Do not continue to Step 3 until the install-path mismatch is resolved -- subsequent sessions will re-enter Case K until then."**
|
|
146
148
|
|
package/SKILL.md
CHANGED
|
@@ -45,20 +45,20 @@ as your FIRST and ONLY response — no summary, no menu, no preamble:
|
|
|
45
45
|
|
|
46
46
|
Then continue with `skills/deft-directive-setup/SKILL.md` Phase 1 for remaining questions.
|
|
47
47
|
|
|
48
|
-
**If USER.md exists but `./
|
|
48
|
+
**If USER.md exists but `./xbrief/PROJECT-DEFINITION.xbrief.json` is missing**: Skip to
|
|
49
49
|
`skills/deft-directive-setup/SKILL.md` Phase 2.
|
|
50
50
|
|
|
51
|
-
**If USER.md and `./
|
|
51
|
+
**If USER.md and `./xbrief/PROJECT-DEFINITION.xbrief.json` both exist but no scope xBRIEFs in `./xbrief/` lifecycle folders**:
|
|
52
52
|
Skip to `skills/deft-directive-setup/SKILL.md` Phase 3. Start the specification interview
|
|
53
53
|
imediately — ask what to build and features as the first question.
|
|
54
54
|
|
|
55
55
|
### ⊗ Project Root vs Framework Internals
|
|
56
56
|
|
|
57
|
-
! When checking for project-level files (`PROJECT-DEFINITION.
|
|
58
|
-
`PRD.md`), ONLY look at `./
|
|
57
|
+
! When checking for project-level files (`PROJECT-DEFINITION.xbrief.json`, scope xBRIEFs,
|
|
58
|
+
`PRD.md`), ONLY look at `./xbrief/` and its lifecycle subdirectories.
|
|
59
59
|
|
|
60
|
-
- ! `./
|
|
61
|
-
- ! `./
|
|
60
|
+
- ! `./xbrief/PROJECT-DEFINITION.xbrief.json` — the user's project config
|
|
61
|
+
- ! `./xbrief/proposed/`, `./xbrief/pending/`, `./xbrief/active/`, `./xbrief/completed/` — scope xBRIEFs in lifecycle folders
|
|
62
62
|
- ⊗ Count ANY file inside `.deft/core/` (canonical) or `./deft/` (legacy pre-v0.27) as a project-level artifact — those are
|
|
63
63
|
framework-internal (e.g. `.deft/core/PROJECT.md`, `.deft/core/specs/`, `.deft/core/templates/`
|
|
64
64
|
are all part of the framework, NOT the user's project)
|
|
@@ -75,7 +75,7 @@ USER.md has two sections with different precedence:
|
|
|
75
75
|
```
|
|
76
76
|
USER.md Personal ← HIGHEST (name, custom rules — always wins)
|
|
77
77
|
↓
|
|
78
|
-
PROJECT-DEFINITION.
|
|
78
|
+
PROJECT-DEFINITION.xbrief.json ← Project-specific (strategy, coverage, languages, tech stack)
|
|
79
79
|
↓
|
|
80
80
|
USER.md Defaults ← Fallback defaults (used when PROJECT-DEFINITION doesn't specify)
|
|
81
81
|
↓
|
|
@@ -85,11 +85,11 @@ USER.md Defaults ← Fallback defaults (used when PROJECT-DEFINITION doesn
|
|
|
85
85
|
↓
|
|
86
86
|
main.md ← General AI behavior
|
|
87
87
|
↓
|
|
88
|
-
scope
|
|
88
|
+
scope xBRIEFs ← LOWEST precedence (requirements in lifecycle folders)
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
**IMPORTANT**: USER.md `Personal` section always wins. For project-scoped settings
|
|
92
|
-
(strategy, coverage, languages), `PROJECT-DEFINITION.
|
|
92
|
+
(strategy, coverage, languages), `PROJECT-DEFINITION.xbrief.json` overrides USER.md `Defaults`.
|
|
93
93
|
|
|
94
94
|
## File Reading Strategy (Lazy Loading)
|
|
95
95
|
|
|
@@ -97,7 +97,7 @@ scope vBRIEFs ← LOWEST precedence (requirements in lifecycle folders)
|
|
|
97
97
|
|
|
98
98
|
1. **Always start with**: `.deft/core/main.md` (general guidelines)
|
|
99
99
|
2. **Check for**: `~/.config/deft/USER.md` (personal overrides - highest precedence)
|
|
100
|
-
3. **Check for**: `./
|
|
100
|
+
3. **Check for**: `./xbrief/PROJECT-DEFINITION.xbrief.json` (project-specific rules)
|
|
101
101
|
4. **Then read language-specific** only if working with that language:
|
|
102
102
|
- `.deft/core/languages/python.md`
|
|
103
103
|
- `.deft/core/languages/go.md`
|
|
@@ -128,8 +128,8 @@ See `.deft/core/tools/taskfile.md` for complete task standards and common comman
|
|
|
128
128
|
|
|
129
129
|
**Spec-Driven Development (SDD)** for new features/projects:
|
|
130
130
|
1. Run `skills/deft-directive-setup/SKILL.md` Phase 3 — sizing gate selects Light or Full path
|
|
131
|
-
2. Light: Interview → scope
|
|
132
|
-
3. Full: Interview → rich narratives in `specification.
|
|
131
|
+
2. Light: Interview → scope xBRIEFs in `xbrief/proposed/` (embedded requirements) → Implement
|
|
132
|
+
3. Full: Interview → rich narratives in `specification.xbrief.json` (approval gate) → scope xBRIEFs → Implement
|
|
133
133
|
|
|
134
134
|
See `.deft/core/coding/testing.md` for complete testing standards.
|
|
135
135
|
|
|
@@ -167,7 +167,7 @@ task project:render # Project config → xbrief/PROJECT-DEFINITION.xbrief.
|
|
|
167
167
|
1. **First time?** If USER.md doesn't exist, run `skills/deft-directive-setup/SKILL.md` Phase 1
|
|
168
168
|
2. Read `.deft/core/main.md` (general guidelines)
|
|
169
169
|
3. Read `~/.config/deft/USER.md` (personal preferences - highest precedence)
|
|
170
|
-
4. Read `./
|
|
170
|
+
4. Read `./xbrief/PROJECT-DEFINITION.xbrief.json` (project rules)
|
|
171
171
|
5. Run `task --list` to see available tasks
|
|
172
172
|
|
|
173
173
|
See `.deft/core/main.md` for complete workflow details.
|
package/Taskfile.yml
CHANGED
|
@@ -370,11 +370,11 @@ includes:
|
|
|
370
370
|
packs:
|
|
371
371
|
taskfile: ./tasks/packs.yml
|
|
372
372
|
optional: true
|
|
373
|
-
# Maintainer-only
|
|
373
|
+
# Maintainer-only packaging lane (#1813 contributor path / #2022
|
|
374
374
|
# Phase 2). `internal: true` hides `core:*` / `ci:*` from `task -l` and
|
|
375
375
|
# blocks direct CLI invocation on consumer installs; only
|
|
376
376
|
# `check:framework-source` below wires them as deps. Consumer `task check`
|
|
377
|
-
# dispatches to `check:consumer` (TS / deft verbs
|
|
377
|
+
# dispatches to `check:consumer` (TS / deft verbs).
|
|
378
378
|
core:
|
|
379
379
|
taskfile: ./tasks/core.yml
|
|
380
380
|
optional: true
|
|
@@ -464,8 +464,15 @@ tasks:
|
|
|
464
464
|
- verify-eval-health-relocation-framework-check
|
|
465
465
|
- verify-eval-triggers-relocation-framework-check
|
|
466
466
|
- vbrief:validate
|
|
467
|
-
- codebase:validate-structure
|
|
467
|
+
- task: codebase:validate-structure
|
|
468
|
+
vars:
|
|
469
|
+
CLI_ARGS: "--enforce"
|
|
468
470
|
- verify:codebase-map-fresh
|
|
471
|
+
- verify:spec-prd-fresh
|
|
472
|
+
# #4095: committed RULE-MAP freshness (byte-identical renderer output).
|
|
473
|
+
- docs:rule-map:check
|
|
474
|
+
# #4099: committed capability index freshness (overlay vs registries).
|
|
475
|
+
- docs:capability-map:check
|
|
469
476
|
- verify-strategy-output
|
|
470
477
|
# #2980 residual: fail-closed product raw-write inventory (allowlist primitives + temporary residual).
|
|
471
478
|
- verify-contained-writes-enforce
|
|
@@ -796,18 +803,16 @@ tasks:
|
|
|
796
803
|
# `triage-bootstrap`) -- a single shared `triage:` include namespace
|
|
797
804
|
# is not supported by go-task v3 (two includes cannot share a key).
|
|
798
805
|
# The aliases below provide the documented `task triage:<verb>`
|
|
799
|
-
# user-facing surface that
|
|
800
|
-
#
|
|
801
|
-
#
|
|
802
|
-
#
|
|
806
|
+
# user-facing surface that xBRIEFs / UPGRADING.md describe. Each alias
|
|
807
|
+
# delegates to the underlying namespaced task and forwards
|
|
808
|
+
# `{{.CLI_ARGS}}` so flags (`--repo`, `--reason`, etc.) reach
|
|
809
|
+
# engine:invoke / packages/cli/dist. The inner tasks in each fragment are
|
|
803
810
|
# `internal: true` so the fragment-namespace forms
|
|
804
811
|
# (`triage-cache:cache`, `triage-actions:accept`, `triage-bulk:bulk-defer`,
|
|
805
812
|
# `triage-bootstrap:bootstrap`) drop out of `task -l`; only the
|
|
806
813
|
# documented `triage:*` aliases below appear in the listing. The
|
|
807
|
-
# internal tasks remain CALLABLE for legacy invocations
|
|
808
|
-
#
|
|
809
|
-
# forms, which continue to dispatch correctly via the fragment
|
|
810
|
-
# include).
|
|
814
|
+
# internal tasks remain CALLABLE for legacy invocations via the fragment
|
|
815
|
+
# include.
|
|
811
816
|
#
|
|
812
817
|
# Aliases are inline at the root Taskfile rather than in a separate
|
|
813
818
|
# fragment because they cross include namespaces and must exist
|
|
@@ -826,10 +831,10 @@ tasks:
|
|
|
826
831
|
# categorized verb list grouped by role (Session-start, State verbs,
|
|
827
832
|
# Read verbs, Lifecycle, Subscription mutation, Archive-rotation /
|
|
828
833
|
# Promote-demote, Activate-complete, Reversibility, Decomposition).
|
|
829
|
-
# The registry + renderer live in
|
|
830
|
-
#
|
|
831
|
-
# `scope:X` alias forwards
|
|
832
|
-
# `
|
|
834
|
+
# The registry + renderer live in
|
|
835
|
+
# packages/core/src/triage/help/registry-data.ts (edit in place; no
|
|
836
|
+
# generator). Each existing `triage:X` / `scope:X` alias forwards
|
|
837
|
+
# `--help` to the same registry via interceptHelp (handler + dispatch).
|
|
833
838
|
#
|
|
834
839
|
# Defined at the root Taskfile (not in a fragment) because the bare
|
|
835
840
|
# target shares the `triage:` / `scope:` prefix with the documented
|
package/UPGRADING.md
CHANGED
|
@@ -9,6 +9,20 @@ Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
|
|
|
9
9
|
|
|
10
10
|
<!-- xbrief-backcompat-2111 -->
|
|
11
11
|
|
|
12
|
+
## Current path
|
|
13
|
+
|
|
14
|
+
Ordinary upgrades use the three-command model. This section is the current recovery path; frozen version-to-version hops stay below as history and keep their existing `UPGRADING.md#` anchors.
|
|
15
|
+
|
|
16
|
+
| Your situation | Run this |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| Ordinary upgrade of an existing Directive project | `npm i -g @deftai/directive@latest`, then `directive update` in the project (`pnpm add -g @deftai/directive@latest` on pnpm) |
|
|
19
|
+
| Not sure, or something looks broken | `directive doctor` |
|
|
20
|
+
| First-time adoption, or a legacy / pre-v0.20 layout | `directive init` |
|
|
21
|
+
|
|
22
|
+
Walkthrough: [Canonical upgrade — npm](#canonical-upgrade--npm-v0551). Multi-version jumps: [Big-jump triage](#big-jump-triage--multi-version-upgrades-start-here). Corporate or mirrored registry: [Corporate or mirrored npm registry](#corporate-or-mirrored-npm-registry). Frozen hop 1: [Frozen pre-v0.20 document-model migration](#frozen-pre-v020-document-model-migration-2068).
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
12
26
|
## Dual policy block recovery (#3609)
|
|
13
27
|
|
|
14
28
|
- **Applies when:** PROJECT-DEFINITION contains both legacy bare `plan.policy` and namespaced `plan["x-directive/policy"]`. The namespaced block wins reads, so the bare block is shadowed even when one or more values match.
|
|
@@ -98,7 +112,8 @@ Install source of truth for this repo is **pnpm** (`packageManager` field; CI us
|
|
|
98
112
|
| `*.vbrief.json` | `*.xbrief.json` |
|
|
99
113
|
| `vBRIEF` / “scope vBRIEF” in guidance | `xBRIEF` / “scope xBRIEF” |
|
|
100
114
|
| `x-vbrief/*` reference tokens | `x-xbrief/*` (and migrate-accepted legacy tokens) |
|
|
101
|
-
| `task vbrief:*`
|
|
115
|
+
| `task vbrief:*` aliases | Prefer `task xbrief:*`; keep `vbrief:*` only as deprecated aliases when required for back-compat |
|
|
116
|
+
| Frozen `task migrate:vbrief` (v0.59.0 hop 1 only) | Current hop 2 is `deft migrate:xbrief` / `task migrate:xbrief`. Frozen hop 1 is **not** a current alias of hop 2. |
|
|
102
117
|
| Envelope keys `vBRIEFInfo` | `xBRIEFInfo` (legacy keys still read-accepted on unmigrated files) |
|
|
103
118
|
|
|
104
119
|
**Why two names existed:** consumer layout and disk SoT moved to `xbrief/` while docs, glossary, and marketing still taught vBRIEF as current. That dual present-day naming is retired (#2907). Schema lineage, fixtures, migrate paths, changelog history, and archive prose may still say vBRIEF — always as **legacy/historical**, never as competing current guidance.
|
|
@@ -358,6 +373,8 @@ Non-native-skill harnesses (Codex CLI, OpenCode) report 0 B frontmatter; set `ha
|
|
|
358
373
|
|
|
359
374
|
## xBRIEF layout migration (#2034 / #2110)
|
|
360
375
|
|
|
376
|
+
This section is **hop 2** for projects already on vBRIEF 0.6 (`vbrief/` lifecycle). Already-current xBRIEF 0.8: skip. Flat pre-v0.20 root docs: start at hop 1 in [Frozen pre-v0.20 document-model migration](#frozen-pre-v020-document-model-migration-2068). ⊗ Pin v0.59.0 or run frozen `migrate:vbrief` for this hop.
|
|
377
|
+
|
|
361
378
|
After upgrading to a release that ships the xbrief rename, convert legacy on-disk layout if `deft doctor` reports a `vbrief/` tree or `x-vbrief/` reference tokens:
|
|
362
379
|
|
|
363
380
|
```bash
|
|
@@ -424,44 +441,67 @@ import schema from "@deftai/directive-types/schemas/xbrief-core-0.8.schema.json"
|
|
|
424
441
|
|
|
425
442
|
### `deft migrate` vs pre-v0.20 document-model migration
|
|
426
443
|
|
|
427
|
-
These commands are unrelated — do not confuse them:
|
|
444
|
+
These three commands are unrelated — do not confuse them:
|
|
428
445
|
|
|
429
|
-
| Command | When to use | What it does |
|
|
430
|
-
| --- | --- | --- |
|
|
431
|
-
| `deft migrate` / `directive migrate` | Canonical-vendored `.deft/core/` deposit after npm upgrade (#1941) | Stamps `managed_by: npm` into the install manifest. Idempotent; never downloads payload. |
|
|
432
|
-
|
|
|
446
|
+
| Command | Runtime | When to use | What it does |
|
|
447
|
+
| --- | --- | --- | --- |
|
|
448
|
+
| `deft migrate` / `directive migrate` | Current npm | Canonical-vendored `.deft/core/` deposit after npm upgrade (#1941) | Stamps `managed_by: npm` into the install manifest. Idempotent; never downloads payload. **Not** document-model migration. |
|
|
449
|
+
| `deft migrate:xbrief` / `task migrate:xbrief` | Current npm | Hop 2: vBRIEF 0.6 (`vbrief/`) → xBRIEF 0.8 (`xbrief/`) | Layout + envelope migration. Current Taskfiles ship this as `migrate:xbrief`. |
|
|
450
|
+
| Frozen `task migrate:vbrief` | **v0.59.0 only** | Hop 1: pre-v0.20 flat `SPECIFICATION.md` / `PROJECT.md` → vBRIEF 0.6 | Python migrator. **Not shipped on current npm.** Current Taskfiles have no `migrate:vbrief` target. |
|
|
433
451
|
|
|
434
452
|
### Frozen pre-v0.20 document-model migration (#2068)
|
|
435
453
|
|
|
436
|
-
Current `@deftai/directive` npm releases no longer ship `task migrate:vbrief` or `scripts/migrate_vbrief.py` on the consumer deposit path (#2022 Phase 3).
|
|
454
|
+
Current `@deftai/directive` npm releases no longer ship `task migrate:vbrief` or `scripts/migrate_vbrief.py` on the consumer deposit path (#2022 Phase 3).
|
|
455
|
+
|
|
456
|
+
**This is a two-hop chain.** The pre-v0.20 flat model does not migrate straight to the current layout:
|
|
457
|
+
|
|
458
|
+
- **Hop 1** — pin **v0.59.0**, run frozen `task migrate:vbrief` (flat → vBRIEF v0.6).
|
|
459
|
+
- **Hop 2** — on **current npm**, run `deft migrate:xbrief` (vBRIEF v0.6 → xBRIEF v0.8). Not `deft migrate`.
|
|
460
|
+
|
|
461
|
+
This file owns the numbered hop commands. [docs/BROWNFIELD.md](./docs/BROWNFIELD.md) should point here rather than restate a second procedure. Live `frozenPreCutoverMigrationGuidance()`, QUICK-START Case H, and README are other envelopes.
|
|
462
|
+
|
|
463
|
+
#### Who runs which hop
|
|
464
|
+
|
|
465
|
+
| Starting layout | Next step |
|
|
466
|
+
| --- | --- |
|
|
467
|
+
| Flat authoritative root `SPECIFICATION.md` / `PROJECT.md` (no vBRIEF/xBRIEF lifecycle) | Hop 1, then hop 2 |
|
|
468
|
+
| Valid vBRIEF 0.6 (`vbrief/` lifecycle) | Hop 2 only — do not pin v0.59.0 |
|
|
469
|
+
| xBRIEF 0.8 with incomplete lifecycle folders | Current repair/validation only. Not hop 1. |
|
|
470
|
+
| Complete xBRIEF 0.8 | No document-model migration |
|
|
471
|
+
|
|
472
|
+
⊗ Pin v0.59.0 or run frozen `migrate:vbrief` on an already-current xBRIEF 0.8 project. Incomplete `xbrief/` is not hop-1 input.
|
|
473
|
+
|
|
474
|
+
`deft doctor` / current `task migrate:preflight` may still print `Pre-cutover: migration needed` for a missing lifecycle folder on an otherwise current tree (runtime `detectPreCutover`). That predicate is not this docs slice. Hop 1 in **this** numbered list is only for flat authoritative root docs.
|
|
437
475
|
|
|
438
|
-
> **Durability & support horizon (#2297).** This is a **best-effort** path for a document model that predates v0.20. The permanence anchor is the **`v0.59.0` git tag** — GitHub serves a source tarball for any tag on demand (`https://github.com/deftai/directive/archive/refs/tags/v0.59.0.tar.gz`), so recovery does **not** depend on any uploaded release asset staying attached.
|
|
476
|
+
> **Durability & support horizon (#2297).** This is a **best-effort** path for a document model that predates v0.20. The permanence anchor is the **`v0.59.0` git tag** — GitHub serves a source tarball for any tag on demand (`https://github.com/deftai/directive/archive/refs/tags/v0.59.0.tar.gz`), so recovery does **not** depend on any uploaded release asset staying attached. Verify the checkout SHA before hop 1: tag `v0.59.0` currently names commit `e8bfd5aa21511a38e4b45b3d5b80edb30e9e2dd0` (a tag is a movable ref). If you cannot reach the frozen payload at all, use the **[Fresh-start fallback](#fresh-start-fallback-2297)** below.
|
|
439
477
|
|
|
440
|
-
**Applies when:**
|
|
478
|
+
**Applies when:** the project still has authoritative pre-v0.20 root `SPECIFICATION.md` / `PROJECT.md` (no `<!-- deft:deprecated-redirect -->` sentinel, and no `vbrief/` or `xbrief/` lifecycle).
|
|
441
479
|
|
|
442
480
|
**Pinned tag:** `v0.59.0` — the last release before the Python-free npm deposit; the tagged tree includes `scripts/migrate_vbrief.py`.
|
|
443
481
|
|
|
444
|
-
**
|
|
482
|
+
**Trust:** run hop 1 only against a **trusted** project checkout. The frozen Python migrator writes under repo-controlled paths (it replaces root docs with redirect stubs). Do not point it at an untrusted tree.
|
|
445
483
|
|
|
446
484
|
**Steps:**
|
|
447
485
|
|
|
448
|
-
1.
|
|
449
|
-
2.
|
|
450
|
-
|
|
451
|
-
- **Git clone /
|
|
486
|
+
1. Confirm the starting layout in the table above. Already-current xBRIEF 0.8: stop. Valid vBRIEF 0.6: skip to hop 2 (step 7).
|
|
487
|
+
2. Install **Python 3.11+** and **[uv](https://docs.astral.sh/uv/)** on the migration machine.
|
|
488
|
+
3. Fetch framework **v0.59.0** and verify SHA `e8bfd5aa21511a38e4b45b3d5b80edb30e9e2dd0` (git-tag methods first — they survive even if release assets are removed):
|
|
489
|
+
- **Git clone (preferred):** `git clone --branch v0.59.0 https://github.com/deftai/directive.git deft-v0.59.0`, then `git -C deft-v0.59.0 rev-parse HEAD` must equal that SHA, or
|
|
490
|
+
- **Source tarball from the tag:** download `https://github.com/deftai/directive/archive/refs/tags/v0.59.0.tar.gz`, extract to a directory, then confirm the tree matches the SHA, or
|
|
452
491
|
- **Frozen Go installer** at [GitHub Releases tag v0.59.0](https://github.com/deftai/directive/releases/tag/v0.59.0) (legacy bridge; relies on the uploaded asset, so prefer a git-tag method above for durability).
|
|
453
|
-
|
|
492
|
+
4. From the **consumer project root** (working directory = the project being migrated), run hop 1 against the **pinned** Taskfile — not the current deposit:
|
|
454
493
|
```bash
|
|
455
|
-
task migrate:
|
|
456
|
-
task migrate:vbrief
|
|
457
|
-
task migrate:vbrief
|
|
494
|
+
task -t /path/to/deft-v0.59.0/Taskfile.yml migrate:vbrief -- --dry-run
|
|
495
|
+
task -t /path/to/deft-v0.59.0/Taskfile.yml migrate:vbrief
|
|
458
496
|
```
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
497
|
+
Frozen `migrate:vbrief` self-invokes `migrate:preflight` on that same pinned Taskfile. Do not run current-npm `task migrate:preflight` as the hop-1 gate. Current deposits have no `migrate:vbrief` target — `task -t ./.deft/core/Taskfile.yml migrate:vbrief` is a dead fallback.
|
|
498
|
+
5. **Hop 1 postcondition** (frozen runtime, not current `deft doctor`): the migrator exits 0, and the project has `vbrief/specification.vbrief.json`, `vbrief/PROJECT-DEFINITION.vbrief.json`, and `vbrief/{proposed,pending,active,completed,cancelled}/`. Root `SPECIFICATION.md` / `PROJECT.md` are deprecation redirects. This is vBRIEF 0.6, not xBRIEF.
|
|
499
|
+
6. Upgrade to current npm: `npm i -g @deftai/directive@latest`, then `deft update` from the project root. Optional: regenerate exports with `task roadmap:render`, `task project:render`, and `task prd:render -- --force` when you maintain a `PRD.md` (frozen-payload renderers; hop 2 will rewrite layout).
|
|
500
|
+
7. **Hop 2:** `deft migrate:xbrief` (or `task migrate:xbrief` from a maintainer checkout). Requires a clean working tree unless `--force`.
|
|
501
|
+
8. **Hop 2 postcondition** (current npm): `deft migrate:xbrief` reports migrated or already done; `xbrief/` exists with `xBRIEFInfo.version` `0.8`; and the xBRIEF signpost is `xBrief migration: none` (or `converged`). A `vbrief/`-only tree must fail this proof. Do not treat `deft doctor` exit 0 as hop-2 proof. `deft migrate` (provenance stamp) is a separate npm-channel step — run it after hop 2 if needed, never instead of hop 2.
|
|
502
|
+
9. Start a **new agent session** so refreshed AGENTS.md and skills load from a clean context.
|
|
463
503
|
|
|
464
|
-
⊗ Run `npm i -g @deftai/directive@latest` / `deft update` on a project that still has authoritative pre-v0.20 root docs — the current deposit cannot run
|
|
504
|
+
⊗ Run `npm i -g @deftai/directive@latest` / `deft update` on a project that still has authoritative pre-v0.20 root docs — the current deposit cannot run hop 1; follow the frozen path first.
|
|
465
505
|
|
|
466
506
|
#### Fresh-start fallback (#2297)
|
|
467
507
|
|
|
@@ -1031,7 +1071,7 @@ The contract is byte-stable by construction:
|
|
|
1031
1071
|
|
|
1032
1072
|
## From any pre-v0.20 version → v0.20.0 (historical; use frozen path)
|
|
1033
1073
|
|
|
1034
|
-
> **Current
|
|
1074
|
+
> **History.** This From-X-to-Y list records the v0.20.0 cutover. It is **not** the current hop-2 instruction. Current hop 2 is `deft migrate:xbrief` in [Frozen pre-v0.20 document-model migration](#frozen-pre-v020-document-model-migration-2068). Commands below assume pinned **v0.59.0** (hop 1 payload only).
|
|
1035
1075
|
|
|
1036
1076
|
- **Applies when:** `deft doctor` / `task migrate:preflight` reports pre-cutover state. Legacy `SPECIFICATION.md` / `PROJECT.md` without the `<!-- deft:deprecated-redirect -->` sentinel is the canonical signal.
|
|
1037
1077
|
- **Safe to auto-run:** No — `task migrate:vbrief` on the pinned release rewrites `SPECIFICATION.md` and `PROJECT.md` into deprecation-redirect stubs and creates lifecycle folders; review `--dry-run` first.
|
package/commands.md
CHANGED
|
@@ -4,7 +4,7 @@ Current command surfaces for scoped work, generated documents, triage/cache work
|
|
|
4
4
|
|
|
5
5
|
Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
|
|
6
6
|
|
|
7
|
-
**See also**: [verification/verification.md](./verification/verification.md) | [resilience/continue-here.md](./resilience/continue-here.md) | [vbrief/vbrief.md](./vbrief/vbrief.md) | [docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md)
|
|
7
|
+
**See also**: [verification/verification.md](./verification/verification.md) | [resilience/continue-here.md](./resilience/continue-here.md) | [vbrief/vbrief.md](./vbrief/vbrief.md) | [docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md) | [docs/capabilities.md](./docs/capabilities.md) (generated capability index; `task docs:capability-map`)
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -107,8 +107,8 @@ On-demand **write + check** dense xBRIEF SoT artifacts at an explicit path. Thes
|
|
|
107
107
|
|
|
108
108
|
| Verb | Meaning |
|
|
109
109
|
|------|---------|
|
|
110
|
-
| `deft xbrief:create`
|
|
111
|
-
| `deft xbrief:verify`
|
|
110
|
+
| `deft xbrief:create` | Write json, md, or both at `--out` |
|
|
111
|
+
| `deft xbrief:verify` | Fail-closed check at `--out` |
|
|
112
112
|
| `scope:*` / intake | Lifecycle birth and folder/status transitions |
|
|
113
113
|
| `xbrief:preflight` | Implementation-intent gate (unchanged) |
|
|
114
114
|
|
|
@@ -146,7 +146,7 @@ Common commands:
|
|
|
146
146
|
- `task scope:fail -- xbrief/active/<file>.xbrief.json` -- mark running work failed when the scope cannot complete.
|
|
147
147
|
- `task scope:cancel -- <path>` -- move a scope to `cancelled/`.
|
|
148
148
|
- `task scope:restore`, `task scope:block`, `task scope:unblock`, `task scope:demote`, and `task scope:undo:*` -- repair or reverse lifecycle transitions.
|
|
149
|
-
- `
|
|
149
|
+
- `deft issue:sync-from-xbrief -- <path>` -- post a GitHub issue comment summarizing material AC/status changes for an origin-linked scope xBRIEF (`plan.references` with `x-xbrief/github-issue`). Supports `--dry-run` (print without posting), `--repo OWNER/NAME` when the reference URI lacks a repo slug, and `--allow-cross-repo` for intentional cross-repo sync (refused by default; #2633). Skips when no material changes since the last successful sync. Closes the reverse-sync gap after `task issue:ingest` (#2540).
|
|
150
150
|
- `task issue:ingest -- <N>` / `task issue:ingest -- --all [--label L] [--status S] [--dry-run]` -- ingest GitHub issues as scope xBRIEFs (deduplicates via existing references).
|
|
151
151
|
- `task reconcile:issues [-- --apply-lifecycle-fixes]` -- scan origin-linked xBRIEFs for stale or closed GitHub issues.
|
|
152
152
|
|
|
@@ -168,7 +168,7 @@ The implementation gate succeeds only for active scope xBRIEFs with `plan.status
|
|
|
168
168
|
|
|
169
169
|
**Slash-command intent containment (#1193):** When a session is originated by a slash command, that command is the *only* authorized verb for the session. Set `DEFT_SESSION_SLASH_VERB` (e.g. `/github-issue`) so `task xbrief:preflight` and PreToolUse hooks enforce the ceiling. Non-implement verbs (`/github-issue`, `/triage`, `/refine`, `/discuss`, `/research`, …) MUST NOT authorize implement, push, PR, merge, or deploy — adjacent bugs noticed during RCA become a second filed issue, not a second PR. Implement verbs: `/build`, `/ship`, `/ship-hotfix`, `/swarm`, `/implement`.
|
|
170
170
|
|
|
171
|
-
**Human merge gate (#1193):** Typed `plan.policy.requireHumanMerge` (defaults true when `plan.policy.autoDeployOnMerge` is true). Agents may open PRs but must not merge when the gate is ON. Surfaces: (1) `task pr:wait-mergeable-and-merge` refuses agent merge, (2) `task verify:branch` advisory note, (3) branch-protection / setup requiring ≥1 human reviewer. Session-start discloses when ON. Override: `
|
|
171
|
+
**Human merge gate (#1193):** Typed `plan.policy.requireHumanMerge` (defaults true when `plan.policy.autoDeployOnMerge` is true). Agents may open PRs but must not merge when the gate is ON. Surfaces: (1) `task pr:wait-mergeable-and-merge` refuses agent merge, (2) `task verify:branch` advisory note, (3) branch-protection / setup requiring ≥1 human reviewer. Session-start discloses when ON. Override: `deft policy:allow-bot-merge -- --confirm` or `DEFT_ALLOW_BOT_MERGE=1`.
|
|
172
172
|
|
|
173
173
|
**Hotfix classifier (#1193):** Typed `plan.policy.hotfixCriteria` + pure `evaluateHotfixEligibility`. Small fix / pure revert may propose label `hotfix-candidate` only; a human promotes to `hotfix`. Refactors, new exports/handlers, and forbidden paths (Dockerfile, fly.toml, workflows, migrations, auth/secrets) never qualify.
|
|
174
174
|
|
|
@@ -286,7 +286,6 @@ Current status: the validation, extractor, provider, registry, generated MAP, an
|
|
|
286
286
|
- `task check:merge` -- explicit merge-chokepoint alias for `check:framework-source` in the framework source repo (#1704).
|
|
287
287
|
- `task check:framework-source` -- framework-source lane.
|
|
288
288
|
- `task check:consumer` -- consumer-shape lane.
|
|
289
|
-
- `task check:slow` -- slower/full checks.
|
|
290
289
|
|
|
291
290
|
### Gate throughput — iteration fast lane (#1704)
|
|
292
291
|
|
|
@@ -302,7 +301,7 @@ Current status: the validation, extractor, provider, registry, generated MAP, an
|
|
|
302
301
|
- `task verify:branch` -- enforce default-branch protection.
|
|
303
302
|
- `task verify:hooks-installed` -- ensure local git hooks are configured; use `deft verify:hooks-installed --scope=agent --live` for fail-closed agent-host registration + command functionality.
|
|
304
303
|
- `task verify:encoding` -- detect mojibake and BOM issues.
|
|
305
|
-
- `task verify:
|
|
304
|
+
- `task verify:vbrief-conformance` -- validate xBRIEF conformance surfaces.
|
|
306
305
|
- `task verify:cache-fresh` -- validate cache freshness where required.
|
|
307
306
|
- `task verify:capacity`, `task verify:wip-cap`, and `task verify:judgment-gates` -- policy/capacity gates.
|
|
308
307
|
- `task verify:orphan-active` -- fail closed when active/running xBRIEFs still point at closed issues or merged PRs (#2321). After merge, `task verify:orphan-active -- --issue N` scans briefs that reference that issue. Confirmed shipped prints `task scope:complete -- <path>`; unresolved lookup prints a retry remediation and still exits 1 (#3429). PR-only briefs stay on the unscoped scan or `task swarm:complete-cohort`.
|
|
@@ -403,7 +402,7 @@ After CLI/deposit upgrade, disk can show the new generation while a long-lived s
|
|
|
403
402
|
|
|
404
403
|
- ! Successful `init` / payload `update` stamps a monotonic live generation at `.deft/GENERATION.json` (outside `.deft/core` so replace does not wipe the counter).
|
|
405
404
|
- ! Mutation `session:start` (cold and re-arm) binds that generation into `.deft/session-bind.json` when payload surfaces load.
|
|
406
|
-
- ! Query with `deft freshness:report` / `
|
|
405
|
+
- ! Query with `deft freshness:report` / `deft session:freshness` (`--json` supported). States: `current` | `stale_soft` | `stale_hard` | `unbound`. Exit `0` only when `current`.
|
|
407
406
|
- ! Rebind without restarting a shared host runtime: re-load surfaces into the session, then `deft freshness:bind` (or re-arm / `session:ready`).
|
|
408
407
|
- ! Mid-mission: park and hand off before a hard refresh; an empty session after refresh is not work complete.
|
|
409
408
|
- Soft vs hard meanings, surfaces, and API: `content/docs/freshness-contract.md`.
|
|
@@ -413,20 +412,22 @@ After CLI/deposit upgrade, disk can show the new generation while a long-lived s
|
|
|
413
412
|
- ! Default interactive sessions to **read-only posture** until mutation or implementation intent (questions, research, Plan Mode, ticket-shaping). Load AGENTS.md / main.md / USER.md / PROJECT-DEFINITION; confirm alignment with addressing-name; ⊗ do not write `.deft/ritual-state.json`, run install/build side effects, or emit triage welcome, branch-policy, default-branch sync, sync-skill lifecycle checks, or eval/value readback writes unless the operator asks or the task is implementation-ready.
|
|
414
413
|
- ! **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
414
|
- ! 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
|
-
- ? Explicit read-only alignment only: `deft session:start --
|
|
415
|
+
- ? Explicit read-only alignment only: `deft session:start --read-only` (no ritual-state write). Task: `task session:start -- --read-only`.
|
|
417
416
|
- ! **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
417
|
- ! **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
418
|
- ! **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
419
|
- ! **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.
|
|
421
|
-
- ! **One actor-resolution chain, four terminals (#3954):** claim, release, heartbeat and grant/revoke resolve the acting session by the same lookup order — explicit `--session-id`, then `DEFT_SESSION_ID`, then the owner the running host published.
|
|
420
|
+
- ! **One actor-resolution chain, four terminals (#3954 / #4066):** claim, release, heartbeat and grant/revoke resolve the acting session by the same lookup order — explicit `--session-id`, then `DEFT_SESSION_ID`, then the owner the running host published. **Claim** is host-authoritative when those disagree: inherited `DEFT_SESSION_ID` must not beat the host-published owner (mirrors the write-gate env drop). Release, heartbeat and grant/revoke still report disagreement without reordering, and still refuse to mint. Anonymous release of the occupant recorded in the lease file stays **refused** — possession of that path is not authority to delete a live lease.
|
|
422
421
|
- ! **Where the transport still does not reach (#3873 residue):** the CLI resolves the host owner; the write gate runs in the `deft-hook` sibling process, and on a deployment where the host does not publish `GROK_SESSION_ID` into that sibling the hook presents whatever `DEFT_SESSION_ID` it inherited — possibly another host's session. Nothing in this tree can set that process's environment, and the hook writes no env or payload log, so the condition is inferred from the deny text rather than observed. Recovery meanwhile is the ambient step above: the occupant releases its own lease from its own shell. Closing it needs either host cooperation (publish the variable to the hook sibling) or a hook-process capture facility, and both are separate work.
|
|
423
422
|
- ! **Lifecycle identity transport (#3611):** for every host with a resolved owner, PreToolUse rewrites only exact, simple canonical `deft` / `directive` lifecycle commands and source-repo `task <verb> [-- ...]` forms to add the host's `--session-id`. Direct CLI spellings are `session:start`, `session:ready`, `session:end`, `occupancy:steal`, `occupancy:release`, `occupancy:heartbeat`, `occupancy:grant` (#3954, its `--revoke` arm included), and `swarm-launch`; the Task spelling for the last verb is `swarm:launch`. For owner-requiring lifecycle commands, the shell execution directory must be absent or realpath-align exactly with the hook project root. Path-bearing executables (`./deft`, `/path/deft`), path/destination flags (`--project-root`, `--paths`, path-valued `--stories`, `--output`, `--worktree-map`, `--gate-clearances`), `--no-audit`, consumer-repo Task indirection, Task aliases (`task deft:<verb>`), and compound, redirected, quoted, aliased, wrapped, or otherwise ambiguous forms are not auto-rewritten. A supported-host hook rejects a recognized lifecycle form outside the narrow rewrite surface until it carries the explicit matching `--session-id`; an execution-root mismatch on an owner-requiring command always denies. With a matching ID on other excluded forms, the original command remains under normal host permission handling. Manual/integrated-terminal callers must likewise pass one matching `--session-id` (or `DEFT_SESSION_ID`) through the complete lifecycle.
|
|
424
423
|
- ! **Transition, steal, and release (#3611):** an existing live UUID lease cannot silently become a host-namespaced owner. Prefer one aligned transition: `session:start --steal --confirm --occupant <reported-session-id> --session-id=<your-session-id>` (an exact host-mediated command receives the final option automatically). Bare `occupancy:steal --confirm --occupant <reported-session-id> --session-id=<your-session-id>` changes only the lease; direct writes remain denied unless ritual state already names the new owner. If they differ, align the same writer ID with `session:start --rearm --session-id=<same-session-id>` when re-arm is eligible, or cold `session:start --session-id=<same-session-id>` otherwise. The occupant drops a live lease with `occupancy:release` or `session:end`; a non-owner cannot clear it. Confirmed steal remains required for a live occupant and prints existing `claimed_at` / `heartbeat_at` / `last_write_at` when available.
|
|
425
424
|
- ! **Lease refresh (#3599):** a gated write by the owner re-stamps `heartbeat_at`, so a session that keeps working keeps its lease, up to the absolute age cap below. The re-stamp is floored at a quarter of the TTL to avoid rewriting the lease per event, and it records `last_write_at` separately — `heartbeat_at` moves on any lease touch, `last_write_at` only on a gated product write, which is what tells a would-be stealer that the occupant is mid-work. When the owner's own lease is inside the staleness window (three quarters of the TTL) and the automatic re-stamp could not run, the write gate says so instead of letting the lease lapse silently; a write that did re-stamp stays quiet, because the warning would name a state that write just cleared. A re-stamp blocked by the lock leaves the lease untouched and the gate re-decides against the file on disk: contention alone keeps the rightful owner writing, while a takeover that completed during the wait denies. Long quiet stretches produce no gated write to ride on, so the owner refreshes explicitly with `deft occupancy:heartbeat` (Task: `task occupancy:heartbeat`). Refresh extends a lease the caller already holds — it never claims a free worktree, never takes a foreign lease, and never mints an owner; an unheld lease exits non-zero. Under a supported host the exact command receives the matching `--session-id` automatically; manual and Grok callers pass `--session-id <id>` or `DEFT_SESSION_ID`.
|
|
426
425
|
- ! **Absolute lease age cap (#3599):** a lease is also dead 12 hours after `claimed_at`, whatever its heartbeat says, and no refresh path may extend that — `claimed_at` survives every re-stamp. Occupancy admits whoever presents the occupant's session id, so refresh alone would let any process holding that string keep a worktree forever and disable the crash-recovery reclaim the TTL exists for. The two dead states call for different responses and read differently: a stale heartbeat means refresh sooner; past the cap the tree is no longer held, so the capped holder's own gated writes are **refused** until it re-claims with `session:start --session-id=<your-session-id>` — allowing them would let the very bearer the cap bounds keep mutating a worktree a peer may claim at any moment. A lease that is both stale and capped reads as capped, because refreshing cannot revive it and the stale wording would send the holder somewhere that does not help. A different session is unaffected: taking over an aged-out tree is the reclaim the cap exists to enable. Twelve hours is sized by the stalled owner, not the busy one: refresh keys on writes, so an agent that finishes overnight and waits for its operator stops refreshing while staying legitimate, and 12 hours spans a 23:00 dispatch to a 09:00 handoff while still bounding reclaim inside a day. Reaching the cap costs one re-claim, never the work. A time cap cannot tell a stalled-but-live owner from a dead one — the only liveness signal on this path is a write; if that bites, the answer is a write-free liveness signal (explicit parked state, or refresh on non-write activity), not a larger number.
|
|
427
426
|
- ! **Lease membership (#3755):** the occupant admits a dispatched child with `deft occupancy:grant --session-id=<owner> --child-session-id=<child> --role <worker-role> [--ttl-minutes N] [--worktree <path>] [--host <id>] [--address <name>] [--join-protocol none|heartbeat-file|parent-message]` (Task: `task occupancy:grant`), and withdraws it with the same command plus `--revoke`. The grant records owner id, child id, worktree, role and expiry, so a write resolves to a session rather than to whoever held the string. Admission splits: **writes** are admitted for the owner **or** a valid unexpired member; **release, steal, heartbeat and cohort close-out stay owner-only**, so a grant never escalates into the lease itself. An expired grant is refused on read, expiry is clamped to the lease's own absolute age cap, a lease carries at most 32 live grants, and a steal or a fresh claim starts with none — grants belong to the lease that issued them. The child id is checked at grant time (#3954): a value under the reserved `host:` prefix must be a well-formed canonical owner, and one that re-prefixes the owner's own host payload under a second provider is refused as the self-grant it is. Both were granted before, and the write gate then admitted them as `member`, so the lease read as membership while admitting nobody. An id outside that prefix is still accepted, because a child on a host with no identity contract presents whatever `DEFT_SESSION_ID` holds. Withdrawal skips the check, so a malformed grant written earlier stays revocable. A member's write re-stamps `heartbeat_at` and `last_write_at` on the same quarter-TTL floor as the owner's: a tree a granted child is actively writing is in use, and letting it lapse would hand the worktree to a peer mid-edit. `claimed_at` is untouched, so the absolute age cap and the grant's own expiry still bound it. The verb is inside the rewrite surface since #3954, so a supported host adds the matching `--session-id`; a `--worktree` rebind stays outside it and must carry the owner explicitly. All of it is cooperative, like the rest of this lease: it names who may write, it does not authenticate them. Ritual state stays single-owner, so a member writes under the occupant's ceremony: the composite hook write gate measures the verified ritual owner against the occupant that issued the grant rather than against the writer, and a revoked or expired member is refused there as well.
|
|
428
|
-
- ! **Parent and child, per identity-source kind (#3954 / #3999):** there is no single answer, so do not look for one. On a **`host-env`** host (Grok) the host publishes a different id into each agent session, so a parent and its dispatched children are **different actors**: each resolves its own owner through the chain above and claims its own worktree
|
|
429
|
-
- ! **
|
|
427
|
+
- ! **Parent and child, per identity-source kind (#3954 / #3999 / #4066):** there is no single answer, so do not look for one. On a **`host-env`** host (Grok) the host publishes a different id into each agent session, so a parent and its dispatched children are **different actors**: each resolves its own owner through the chain above and claims **its own worktree**. Membership is **not** automatic there — 32 grants at a four-hour expiry against a twenty-minute lease means granting on every dispatch exhausts a busy parent's lease inside a day — and the revocation trigger stays the owner's own `--revoke` or the grant's expiry. Spawned mutating work takes a reserved linked worktree before occupancy claim; sharing the primary checkout with a live occupant is refuse, not grant-across-host. On a **`payload`** host (Codex, Claude Code, Cursor) parent and subagents share one id, so there is no foreign child lease to admit and nothing to grant on the same tree; own-tree children still record a dispatch lease. A parent's `occupancy:release` on the parent tree does not drop a child tree. No new reap verb.
|
|
428
|
+
- ! **Spawn occupancy seam (#4066):** implement-class spawn (`Task`, `spawn_subagent`, `start_agent`, …) inspects `tool_input.isolation=worktree` / `worktree_path` / `cwd`. Absent field fails closed (do not inherit parent cwd). Unique dispatch reservation (incarnation) is persisted before launch. Occupancy consult is on the destination tree, not a write-gate flip with `actor=null`. Explore and ephemeral spawns stay exempt. Grok PreToolUse cannot rewrite spawn input; hosts that can (`claude`, `cursor`, `codex`) re-root cwd onto the reserved tree. Primary-checkout claim is the exception (`release-cut`, `policy-restore`, `operator-default-branch`) from a trusted producer; `--read-only` never claims.
|
|
429
|
+
- ! **Dispatcher-owned terminal release (#4066 / #3999):** recorded-child close-out is dispatcher lifecycle on a dispatch-provenance `(owner, worktree, incarnation)` tuple. Release requires parent-id match, incarnation match, skip invalid heartbeats, and refuse a tree that is not the heartbeat tree or a dispatcher-allocated tree. Ordinary self-claim records are not close-out. Payload-kind skip remains for same-tree shared identity; a linked worktree distinct from the observer is released. Heartbeats should echo `incarnation` from the dispatch envelope.
|
|
430
|
+
- ! **Lifetime and enforcement boundaries:** expired heartbeat (20 min) is free for claim-over-expired, and the release path may clear residue; no `reap` verb. No host-to-lease map or credential file is persisted; supported hooks re-derive their owner from each payload. Gated writes renew the heartbeat (#3599), so the 20-minute window runs from the owner's last write rather than from its claim, bounded by the absolute age cap above. Missing or drifted hooks remain #3742. Implement-class spawn is occupancy-consulted on the destination worktree (#4066); explore/ephemeral spawn stay outside that consult. Join negotiation is owner-issued membership (`occupancy:grant`, #3755); the parked child-initiated `occupancy:request` queue stays unimplemented and is no longer named in remediation. `swarm:launch` carries the same explicit owner and persists `occupancy_session_id` in a cohort-keyed record; close-out uses that cohort entry as authority, requires any ambient owner to corroborate it, and never substitutes the current live lease owner. Swarm close-out stays `releaseSwarmOccupancy` on complete-cohort.
|
|
430
431
|
- ~ Operators MAY still explicitly request full `deft session:start`, `deft triage:welcome`, sync, or doctor in read-only sessions.
|
|
431
432
|
|
|
432
433
|
### Assist / research posture (#1802)
|
|
@@ -455,17 +456,17 @@ Cross-link: spawn three postures and deny recoveries live under § Agent-host di
|
|
|
455
456
|
### Mutable ritual (mutation posture)
|
|
456
457
|
|
|
457
458
|
- ! On **mutation** session start, run `deft session:start` (or `task session:start` in framework source) after loading AGENTS.md. Records quick-tier ritual in `.deft/ritual-state.json`: alignment confirmation, branch-policy disclosure, `deft verify:tools` guidance, default-branch sync warnings, and `deft triage:welcome` one-liner. State is worktree- and HEAD-bound; stale after `plan.policy.sessionRitualStalenessHours` hours (default 4). Mutation start also claims the worktree occupancy lease (`.deft/occupancy.json`); see Session routing (#3433).
|
|
458
|
-
- ! **Orientation compression Now (#3286):** mutation cold `session:start` composes `doctor` + #3282 toolchain preflight (and deposit-sha fast-paths for `agents:refresh` / `verify:cache-fresh`) as inline sections with per-section status lines — composition of existing steps, not a new monolith. When the deposit fingerprint (payload + templates + engine) is unchanged, refresh surfaces print one-line `unchanged - sha match` no-ops. Opt-in compact output: `deft session:start --
|
|
459
|
+
- ! **Orientation compression Now (#3286):** mutation cold `session:start` composes `doctor` + #3282 toolchain preflight (and deposit-sha fast-paths for `agents:refresh` / `verify:cache-fresh`) as inline sections with per-section status lines — composition of existing steps, not a new monolith. When the deposit fingerprint (payload + templates + engine) is unchanged, refresh surfaces print one-line `unchanged - sha match` no-ops. Opt-in compact output: `deft session:start --compact` or `DEFT_SESSION_COMPACT=1` (verbose remains the default). #2176 read-only default is unchanged. Dual-path Later (orient) stays open until run-summary telemetry shows ritual+gate share ≥ 25% after Now ships (#2899).
|
|
459
460
|
- ! Cold `session:start` does **not** run the live agent-hook probe. Functional readiness belongs to the gated mutation path so cold ceremony retains the #2990/#2991 latency profile.
|
|
460
461
|
- ! **Hot path latency (#2991):** by default, mutation `session:start` does **not** block ritual-state write on optional network. It skips the npm release-availability probe and triage cache empty-hydrate / self-heal (`ensureTriageCacheHydrated` / `maybeSelfHealCache`). Targets (operator-facing, not CI-hard): warm hot path typically under a few seconds once tools are on PATH; cold path dominated by local `verify:tools` and git, usually well under ~30s when optional network is off. Empty-cache GitHub fetch-all and npm `view` previously accounted for multi-minute hangs in the WWYSYDH pilot — those stay off the critical path unless opted in.
|
|
461
462
|
- ! **Cold vs re-arm ceremony tiers (#2992):** default `session:start` is the **cold** (full) path. After age staleness or compact re-arm (#2113) on the **same worktree** with continuous HEAD and previously-passing quick steps, prefer `deft session:start --rearm` (alias `--tier=rearm`) to refresh the ritual clock + HEAD/worktree bind without `verify:tools`, triage welcome, release probe, or staleness tickler. Full cold remains required for missing/invalid state, worktree change, discontinuous HEAD, first install, or failed/missing quick steps. Compact marks `rearm_needed`; PreToolUse denial and inspect/verify messages prefer re-arm recovery when cold is unnecessary.
|
|
462
|
-
- ? Opt into optional network: `deft session:start --
|
|
463
|
+
- ? Opt into optional network: `deft session:start --with-network` or `DEFT_SESSION_START_NETWORK=1`. When enabled, the bounded release-availability probe runs against the public npm registry (skips framework source checkouts, non-release pins, and `DEFT_NO_NETWORK=1`; identical latest-version notices throttle for 24 hours in `xbrief/.triage-cache/release-availability-state.json`). Default-mode triage welcome then also hydrates/self-heals the triage cache. This is separate from `deft doctor`, whose bare and gated invocations remain offline by default (#2182). Refs #1692 / #2991. Re-arm never runs optional network.
|
|
463
464
|
- ~ `session:start --json` includes `steps[]` with `name` + `duration_ms` for major phases (`alignment`, `branch_policy`, `verify_tools`, `triage_welcome`, `release_probe`, `ritual_write`), plus total `duration_ms`, `optional_network`, and `ceremony_tier` (`cold` | `rearm`). Skipped optional steps report `skipped: true` and `duration_ms: 0`. Use this for attribution when investigating ceremony wall-clock.
|
|
464
465
|
- ~ **Process-cost events (#2994 / #3508):** on mutation `session:start` completion (cold or re-arm), Directive appends a local `session:start` behavioral event to `.deft-cache/events.jsonl` with `ceremony_tier`, `duration_ms`, `exit_code`, and optional `steps[]` (same labels as `--json`). Mutation `session:start` also prints one operator-visible `ceremony <tier> <ms>` line (hidden under `--compact` / `DEFT_SESSION_COMPACT`). When PreToolUse denies for `ritual-not-ready`, a local `session:ritual-blocked` event records `tool_name`, `code`, and optional `recovery_tier` / `detail`. Always-on best-effort (never blocks ceremony or deny path); not gated on `valueFeedback`; **no remote upload** (Product Insights #2603 is a separate opt-in). Pull the rollup with `task value:show` (composed reader; CLI process time, not agent-turn wall clock). See § Process-cost events below. ⊗ Do not use the printed CLI duration as #3286 Later graduation input.
|
|
465
466
|
- ~ At safe idle points (clean tree, no in-flight story), mutation session start and `deft scope:complete` may also run the staleness tickler: an interactive, consent-based offer to upgrade Directive (`npm i -g @deftai/directive@latest`) and/or migrate xBRIEF (`deft migrate:xbrief`). Escalation tiers, snooze windows, and opt-out live under `plan.policy.stalenessTickler` — inspect with `deft policy:show --field=stalenessTickler`. State persists in `xbrief/.triage-cache/staleness-tickler-state.json`. Skips framework source checkouts, dirty trees, CI/headless (`DEFT_SESSION_RITUAL_SKIP=1`), and typed opt-out. Refs #2488 / #2489.
|
|
466
|
-
- ! Before any code-writing tool call or `start_agent` implementation dispatch, run `deft verify:session-ritual -- --tier=gated`. Gated tier fails closed unless quick-tier state is fresh; lazily records the non-deferrable `agent_hooks` readiness gate plus `deft doctor` and `
|
|
467
|
+
- ! Before any code-writing tool call or `start_agent` implementation dispatch, run `deft verify:session-ritual -- --tier=gated`. Gated tier fails closed unless quick-tier state is fresh; lazily records the non-deferrable `agent_hooks` readiness gate plus `deft doctor` and `task verify:cache-fresh` entrypoints. Agent-hook correctness is independent of doctor warnings and throttling. Step 0 of the pre-`start_agent` gate stack.
|
|
467
468
|
- ! **One-shot recovery (#2993 / #3100):** when PreToolUse denies writes for a stale/missing gated ritual, run `deft session:ready` (or `task session:ready`). It composes `session:start` (only when quick-tier is not green) + `verify:session-ritual -- --tier=gated` + `cache fetch-all --force` when `cache_fresh` is the remaining blocker, then re-verifies. Even when gated inspect is already fresh, the fast path forces one live `agent_hooks` check so later drift cannot hide behind cached ritual state; it still avoids unnecessary fetch-all. Flags: `--json`, `--repo OWNER/NAME`, `--with-network` (forwarded to session:start). Prefer this over juggling the multi-step recovery sequence under hook pressure.
|
|
468
|
-
- ? Postpone with `deft session:start --
|
|
469
|
+
- ? Postpone with `deft session:start --defer step=reason` (`alignment`, `branch_policy`, `triage_welcome`, `doctor`, `cache_fresh`). `agent_hooks` is non-deferrable.
|
|
469
470
|
- Headless workers / CI MAY set `DEFT_SESSION_RITUAL_SKIP=1`; verifier exits 0 but warns when bypass hides failure.
|
|
470
471
|
- ⊗ Self-report ritual complete without fresh `deft session:start` state; ⊗ bypass `deft verify:session-ritual` before implementation dispatch; ⊗ reorder/skip/merge ritual tiers without operator override.
|
|
471
472
|
|
|
@@ -486,7 +487,7 @@ Agents use this signal to prefer portable syntax and quote zsh-sensitive data su
|
|
|
486
487
|
- Credential bridging: host-gh (`gh auth login` in the execution env) or injected-token (`GH_TOKEN` / `GITHUB_TOKEN` / `GH_ENTERPRISE_TOKEN`). Never put token values in prompts or transcripts.
|
|
487
488
|
- Contract: `content/contracts/scm-readiness.md`; operator docs: `content/scm/github.md` § Mismatched/headless SCM readiness.
|
|
488
489
|
|
|
489
|
-
**Pre-`start_agent` gate stack (#1149/#1348):** (0) `deft verify:session-ritual -- --tier=gated` → (1) `deft verify:story-ready` → (2) `deft xbrief:preflight` → (3) `
|
|
490
|
+
**Pre-`start_agent` gate stack (#1149/#1348):** (0) `deft verify:session-ritual -- --tier=gated` → (1) `deft verify:story-ready` → (2) `deft xbrief:preflight` → (3) `task verify:cache-fresh` → (4) `deft verify:branch` + hooks → (5) `start_agent`.
|
|
490
491
|
|
|
491
492
|
```mermaid
|
|
492
493
|
flowchart TD
|
|
@@ -595,7 +596,8 @@ Directive does not guess your mix. Either you name the next units in order (**or
|
|
|
595
596
|
- `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
597
|
- `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
598
|
- **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
|
-
- **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
|
+
- **Design-critique catalog chip (#3642 / #4205).** Parent attach of `triage-ready` / `recut-needed` / recut `mechanism-shaped` MUST use `task scm:issue:design-critique-chip -- --issue N --chip triage-ready|mechanism-shaped|recut-needed [--repo OWNER/NAME]` (or `deft scm issue design-critique-chip`). Closed catalog remaining-set replace, one write. Auto-stamp chip from `resolveAutoStampCatalogChip` (`Recut:` token → recut-needed). ⊗ `gh api POST .../labels`. ⊗ additive `scm:issue:edit --add-label`.
|
|
600
|
+
- **Work claim (#4200).** Same-issue busy flag `status:claimed`. `task scm:issue:work-claim -- claim|show|release --issue N [--repo OWNER/NAME]` (`deft scm issue work-claim`). Session-start and `xbrief:preflight` MUST show. Warn is success; not a lock. Claim refuses read-only / no occupancy. Last-write-wins: the board can lie about who. v1 does not detect two-issue path overlap. Catalog in `.github/ISSUE_LABELS.md`; ⊗ invent the name per issue.
|
|
599
601
|
- **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
602
|
|
|
601
603
|
### Cache Tasks
|