@deftai/directive-content 0.96.0 → 0.98.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.
Files changed (38) hide show
  1. package/.agents/skills/deft-directive-portfolio-priority/SKILL.md +11 -0
  2. package/Taskfile.yml +6 -0
  3. package/UPGRADING.md +9 -6
  4. package/commands.md +17 -2
  5. package/contracts/test-boundary.md +18 -0
  6. package/docs/consumer-check-contract.md +64 -0
  7. package/docs/deft-directive-disable.md +6 -0
  8. package/docs/delivery-attempt.md +173 -0
  9. package/docs/openclaw-agent-host.md +36 -1
  10. package/docs/operator-log-hygiene-checklist.md +57 -0
  11. package/docs/operator-log-hygiene-consumer-pack-stub.md +75 -0
  12. package/docs/scope-provenance.md +54 -0
  13. package/docs/test-boundary.md +43 -0
  14. package/main.md +46 -0
  15. package/meta/philosophy.md +10 -0
  16. package/package.json +1 -1
  17. package/packs/patterns/patterns-pack-0.1.json +10 -0
  18. package/packs/skills/skills-pack-0.1.json +22 -5
  19. package/patterns/operator-log-hygiene.md +130 -0
  20. package/scm/github.md +26 -0
  21. package/skills/deft-directive-article-review/SKILL.md +17 -6
  22. package/skills/deft-directive-build/SKILL.md +41 -0
  23. package/skills/deft-directive-portfolio-priority/SKILL.md +144 -0
  24. package/skills/deft-directive-release/SKILL.md +22 -5
  25. package/skills/deft-directive-review-cycle/SKILL.md +150 -0
  26. package/skills/deft-directive-swarm/SKILL.md +14 -0
  27. package/skills/deft-directive-swarm/references/core-ops.md +14 -2
  28. package/skills/deft-directive-swarm/references/core-phase-0.md +34 -1
  29. package/skills/deft-directive-swarm/references/core-phase-3.md +6 -0
  30. package/skills/deft-directive-swarm/references/core-phase-4.md +21 -2
  31. package/skills/deft-directive-swarm/references/core-phase-5-6.md +17 -0
  32. package/skills/deft-directive-swarm/references/host-openclaw.md +4 -0
  33. package/tasks/engine-invoke.cjs +22 -17
  34. package/tasks/engine-invoke.test.cjs +30 -0
  35. package/tasks/verify.yml +30 -0
  36. package/templates/agent-prompt-preamble.md +8 -0
  37. package/templates/agents-entry.md +10 -0
  38. package/templates/swarm-greptile-poller-prompt.md +4 -2
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: deft-directive-portfolio-priority
3
+ description: >-
4
+ Pre-promotion portfolio prioritization: cluster competing open RFCs/issues
5
+ from the local github-issue cache, emit a propose-not-apply priority brief
6
+ (conflict matrix, shortlist, park), with epistemic citation gates, then hand
7
+ off for operator dispose. Use when the operator asks for portfolio priority,
8
+ a priority brief, competing RFCs, or to cluster open issues.
9
+ ---
10
+
11
+ Read and follow: skills/deft-directive-portfolio-priority/SKILL.md
package/Taskfile.yml CHANGED
@@ -421,6 +421,9 @@ tasks:
421
421
  - verify:branch
422
422
  - verify:encoding
423
423
  - verify:forward-coverage
424
+ - verify:test-boundary
425
+ - verify:scope-provenance
426
+ - verify:consumer-check-contract
424
427
  - verify:vbrief-conformance
425
428
  - verify:destructive-gh-verbs
426
429
  - verify:scm-boundary
@@ -461,6 +464,9 @@ tasks:
461
464
  - verify:cache-fresh
462
465
  - verify:wip-cap
463
466
  - verify:orphan-active
467
+ - verify:test-boundary
468
+ - verify:scope-provenance
469
+ - verify:consumer-check-contract
464
470
  - vbrief:validate
465
471
  - verify-strategy-output
466
472
  cmds:
package/UPGRADING.md CHANGED
@@ -260,26 +260,29 @@ The `deft-directive-sync` skill (and any agent following this upgrade path) MUST
260
260
  - ! Missing global CLI → remediate with `npm i -g @deftai/directive@latest` (not GitHub release-asset archaeology).
261
261
  - ! Git submodule update remains **legacy / back-compat only**; npm + `directive update` / `deft update` is the primary path.
262
262
 
263
- ### One upgrade PR shape (#3127)
263
+ ### One upgrade PR shape (#3127 / #3193)
264
264
 
265
- A normal framework upgrade is **one PR**, not two stacked PRs. The deposited `deft-core-guard` (`no-mixed-core-and-app`, #1430) allowlists the upgrade co-travel unit so deposit + pin + freshness stamp land together:
265
+ A normal framework upgrade is **one PR**, not two stacked PRs. The deposited `deft-core-guard` (`no-mixed-core-and-app`, #1430) allowlists the upgrade co-travel unit so deposit + pin + freshness stamp land together — and **content-constrains** package/lock when they co-travel with `.deft/core/**` (#3193):
266
266
 
267
267
  | Include in the upgrade PR | Why |
268
268
  | --- | --- |
269
269
  | `.deft/core/**` | Framework deposit payload |
270
270
  | Existing installer-managed deposits (`AGENTS.md`, hooks, skill stubs, slash commands, Taskfile include, `xbrief/.deft-version`, …) | Already framework-adjacent |
271
- | `package.json` + lockfile (`package-lock.json` / `pnpm-lock.yaml` / `yarn.lock`) when the change is the `@deftai/directive` pin (and lock follow-through) | npm pin doctor compares to deposit; part of the upgrade unit |
272
- | `.deft/GENERATION.json` | Live freshness stamp from `init` / `update` (#3117) |
271
+ | `package.json` when the **only** dependency-key changes are `@deftai/directive*` under `dependencies` / `devDependencies` / `optionalDependencies` / `peerDependencies` (not scripts/settings that merely contain the substring) | npm pin doctor compares to deposit; pin unit only (#3193) |
272
+ | lockfile (`package-lock.json` / `pnpm-lock.yaml` / `yarn.lock`) when changes are **follow-through** for that pin (Directive identity + necessary transitive/resolution lines), not unrelated direct product dependency identity | Lock follow-through for the pin unit (#3193) |
273
+ | `.deft/GENERATION.json` | Live freshness stamp from `init` / `update` (#3117); remains path-allowlisted |
273
274
 
274
275
  | Keep out of the upgrade PR | Why |
275
276
  | --- | --- |
276
277
  | Application source, tests, product docs | True app/product work — guard still fails if mixed with `.deft/core/**` |
278
+ | Unrelated `package.json` fields (scripts, metadata, non-Directive deps) co-travelling with deposit | Content-aware guard rejects (#3193); path allowlist alone is not enough |
279
+ | Unrelated lock direct product dep bumps riding the pin exemption | Content-aware guard rejects (#3193) |
277
280
  | Consumer kit narrative / host prose not deposited by Directive | Not installer-managed |
278
281
  | Arbitrary playbooks, cast, features | Product scope, not upgrade |
279
282
 
280
- **Do not** split a routine version bump into “deposit-only” then “pin/GENERATION” PRs — that re-creates engine / deposit / pin skew between merges. **Do** keep product feature work on a separate branch/PR from the framework upgrade.
283
+ **Do not** split a routine version bump into “deposit-only” then “pin/GENERATION” PRs — that re-creates engine / deposit / pin skew between merges. **Do** keep product feature work on a separate branch/PR from the framework upgrade. Consumers should **not** hand-roll a forked `deft-core-guard.yml` for normal upgrades — the deposited workflow already enforces pin-only + lock follow-through.
281
284
 
282
- Refs: [#3127](https://github.com/deftai/directive/issues/3127), [#1430](https://github.com/deftai/directive/issues/1430), [#3117](https://github.com/deftai/directive/issues/3117).
285
+ Refs: [#3127](https://github.com/deftai/directive/issues/3127), [#3193](https://github.com/deftai/directive/issues/3193), [#1430](https://github.com/deftai/directive/issues/1430), [#3117](https://github.com/deftai/directive/issues/3117).
283
286
 
284
287
  Machine-readable skill exit line (for agents/operators):
285
288
 
package/commands.md CHANGED
@@ -300,7 +300,20 @@ When the workflow needs an Approach 1 monitor, scope the Cursor leaf `stop-at: p
300
300
  - Repair missing/drifted entries: `deft update`.
301
301
  - **Refresh and opt-out (#2790, #2752):** Upgrade `@deftai/directive`, then run `deft update` to refresh all four deposits to the fast path; do not hand-edit host hook files. Set `plan.policy.hostHooks.<host>` to `false` only when you deliberately need to disable a host's Tier-1 enforcement — it is not the performance fix. When a host is opted out, `deft update` / `directive init` skip creating or re-merging Directive-managed hook entries for that host; if a prior deposit left managed entries in the file, the next update strips only those entries and preserves unrelated settings. Inspect with `deft policy:show --field=hostHooks`. Doctor and `verify:hooks-installed --scope=agent` treat opted-out hosts as healthy — they do not recommend `deft update` to repair them.
302
302
  - **Claude matcher scope:** Once `.claude/settings.json` hooks are loaded, Claude's `PreToolUse` matcher keys on tool names (`Edit`, `Write`, …), not target paths — matched tools can be gated for the whole session, including writes outside the project tree. Opt out of Claude hook deposit when that posture is unwanted.
303
- - **Compact re-arm (#2113 / #2992 / #2993):** Cursor `preCompact` and Claude/Grok `PreCompact`/`PostCompact` call `deft-hook --event session.compact` to mark the gated session ritual stale after context compaction/resume (`rearm_needed`). Prefer `deft session:ready` (#2993) as the one-shot recovery path. Multi-step remains valid: `deft session:start --rearm` (preferred when worktree/HEAD allow) or full `deft session:start`, then `deft verify:session-ritual -- --tier=gated`. Codex has no native compact hook operators must re-run the mutation ritual manually after compaction.
303
+ - **Compact re-arm + soft AGENTS re-bind (#2113 / #2992 / #2993 / #3171 / #2769):** post-compact posture is **two surfaces**:
304
+ - **Hard (Tier-1):** Cursor `preCompact` and Claude/Grok `PreCompact`/`PostCompact` call `deft-hook --event session.compact` to mark the gated session ritual stale (`rearm_needed`). Prefer `deft session:ready` (#2993) as the one-shot recovery path. Multi-step remains valid: `deft session:start --rearm` (preferred when worktree/HEAD allow) or full `deft session:start`, then `deft verify:session-ritual -- --tier=gated`. Soft **never** replaces or weakens hard deny for writes.
305
+ - **Soft:** the same hook path (and `session.start`) injects a **shared** AGENTS re-bind checklist (re-read AGENTS.md → confirm key rules → deposit integrity → summary≠SoT → operational-ask trap → mutation vs read-only). Soft fires without requiring a write tool; read-only/operational turns do **not** force full cold `session:start`. Soft never authorizes skipping the mutation ritual for writes.
306
+ - **Per-host matrix (#3171):**
307
+
308
+ | Host | Hard compact | Soft re-bind | Wire |
309
+ |------|--------------|--------------|------|
310
+ | **Cursor** | Yes (`preCompact`) | Required | compact `user_message` + SessionStart `additional_context` |
311
+ | **Claude Code** | Yes (`PreCompact`/`PostCompact`) | Required | compact + SessionStart `additionalContext` |
312
+ | **Grok Build** | Yes | Required (#3161 dogfood) | compact + SessionStart soft cue |
313
+ | **Codex** | **No** native compact | Docs + best-effort | SessionStart soft cue only; operators re-arm mutation ritual manually after compaction |
314
+ | **OpenClaw** | Not file-host hooks | Required | durable workspace skill `deft-directive-post-compact-rebind` via `deft doctor --fix` / init; see [openclaw-agent-host.md](./docs/openclaw-agent-host.md) |
315
+
316
+ - Shared checklist SoT: `packages/core/src/session/compact-ritual.ts` (all host deposits derive from it).
304
317
  - Codex project hooks are trust-gated by Codex. Directive can verify structural registration and command functionality, but reports trust separately as `manual-review-required` and interception as `not-directly-verified`; after an install or changed hook hash, open `/hooks` in Codex and review/approve the exact project hook commands. Runtime trust and real host interception cannot be inferred from the file or live shim probe alone.
305
318
  - Directive writes only `.codex/hooks.json`; it does not parse or modify `.codex/config.toml`. Codex can also load inline hooks from `config.toml`, so avoid defining duplicate Directive commands there or they may run more than once. See the [Codex hooks documentation](https://learn.chatgpt.com/docs/hooks).
306
319
  - The P0 hook slice does not classify shell-mediated *file* writes, richer unified-exec calls, or WebSearch by default. **Runtime authority (#1394 / #2711)** adds opt-in path allow/deny lists and graduated `scopes` (`edits`, `push`, `merge`) under `plan.policy.runtimeAuthority` — inspect with `deft policy:show --field=runtimeAuthority`. When `enabled: true`, PreToolUse denies classifiable direct-write targets outside `allowPaths` or matching `denyPaths` after ritual/scope/read-only gates; `scopes.edits` gates all direct writes. `scopes.push` / `scopes.merge` deny classifiable Shell/Bash (`git push`, `gh pr merge`) and classifiable MCP push/merge tool names; unclassifiable shell/MCP calls fail open (see `content/contracts/runtime-authority.md`). **Unified path write fence (#516 / #2443 / #2948 Wave 3):** PreToolUse also intersects project allow/deny with the active story’s `plan.metadata.swarm.file_scope` via `resolveWriteFence` (single evaluation SoT; optional `writeScope` alias normalizes at read-time only). Full contract: `content/contracts/path-write-fence.md`.
@@ -464,6 +477,8 @@ User-facing surface for the Phase 0 triage workflow and the unified content cach
464
477
 
465
478
  Directive does not guess your mix. Either you name the next units in order (**ordered plan**), or you let the ranked backlog suggest (**queue**). Labels bias the queue; they do not override an active plan.
466
479
 
480
+ **See also (pre-promotion portfolio):** when the need is to cluster competing RFCs/issues into a propose-not-apply priority brief (not single-item queue ranking), use `skills/deft-directive-portfolio-priority/SKILL.md` (#3201 / #3198) — classify is filter-only; no SCM label writes.
481
+
467
482
  | Path | When | Who sets it | Bare "what's next?" means |
468
483
  |---|---|---|---|
469
484
  | **Ordered plan** | You know the next few units (A then B then stop) | `task plan-sequence:set -- --file <json>` | Current sequence entry only; exhaustion fails closed |
@@ -490,7 +505,7 @@ Directive does not guess your mix. Either you name the next units in order (**or
490
505
  - `task triage:reset -- <issue>` -- append a reset record so a candidate can be reconsidered.
491
506
  - `task triage:bulk-accept|bulk-reject|bulk-defer|bulk-needs-ac` -- apply predictable decisions over filtered cached candidates.
492
507
  - `task triage:summary`, `task triage:scope`, `task triage:scope-drift`, `task triage:subscribe`, `task triage:unsubscribe`, `task triage:classify`, `task triage:welcome`, and `task triage:smoketest` -- supporting workflow and onboarding commands.
493
- - `task triage:classify -- --mirror [--apply] [--include-closed] [--author LOGIN|@me] [--repo owner/name] [--batch-size N] [--delay-ms N] [--sample-limit N] [--json]` -- **Bootstrap mass-triage / Tier-1 SCM label mirror (#1423 Wave 1–2 / #3125, #3129).** Runs the existing classify engine over the github-issue cache and mirrors outcomes as labels (`triaged` idempotency marker + optional `plan.policy.triageLabelMirror.actionLabels`). **Default state filter is open-only** (opt-in `--include-closed` for closed archive stamps). Optional `--author` / `--author-mine` scopes plan/apply to matching `author.login` (AND with open-only; digest surfaces the filter) (#3129). Dry-run by default: operator digest with totals (scanned/planned/already_triaged/no_match/closed_skipped/author_skipped/errors), breakdown by **state / rule / action**, and samples (not a full dump as primary UX); `--json` includes the same aggregates. `--apply` writes via the SCM label client / repo-mutation boundary in **batches** (`--batch-size`, default 10) with **rate-limit delay** (`--delay-ms`, default 1000), reports partial failures, and is idempotent on re-run (already-`triaged` skip). Missing labels fail closed per issue with a create-label hint. **Never** calls `triage:accept` and **never** writes `proposed/` xBRIEFs. Wave 3 (agent Tier-2 comments) remains out of scope.
508
+ - `task triage:classify -- --mirror [--apply] [--re-enrich] [--include-closed] [--author LOGIN|@me] [--repo owner/name] [--batch-size N] [--delay-ms N] [--sample-limit N] [--json]` -- **Bootstrap mass-triage / Tier-1 SCM label mirror (#1423 Wave 1–2 / #3125, #3129, #3197).** Runs the existing classify engine over the github-issue cache and mirrors outcomes as labels (`triaged` idempotency marker + optional `plan.policy.triageLabelMirror.actionLabels`). **Default state filter is open-only** (opt-in `--include-closed` for closed archive stamps). Optional `--author` / `--author-mine` scopes plan/apply to matching `author.login` (AND with open-only; digest surfaces the filter) (#3129). Dry-run by default: operator digest with totals (scanned/planned/already_triaged/no_match/closed_skipped/author_skipped/errors), breakdown by **state / rule / action**, and samples (not a full dump as primary UX); `--json` includes the same aggregates. `--apply` writes via the SCM label client / repo-mutation boundary in **batches** (`--batch-size`, default 10) with **rate-limit delay** (`--delay-ms`, default 1000), reports partial failures, and is idempotent on re-run (already-`triaged` skip). **Re-run vs re-enrich (#3124 / #3197):** default re-run keeps the one-shot stamp (`skipped_already_triaged`). After `actionLabels` / auto-classify rule / hold-marker changes, opt in with **`--re-enrich`** (still dry-run by default; pair with `--apply` to write) to re-classify already-stamped issues and plan **additive** label deltas only (v1 never removes obsolete chips; never full reconcile). Digest distinguishes `kind=first-time` vs `kind=re-enrich` planned/applied rows (`planned_kind` / `re_enrich_planned`). Missing labels fail closed per issue with a create-label hint. **Never** calls `triage:accept` and **never** writes `proposed/` xBRIEFs. Wave 3 (agent Tier-2 comments) remains out of scope.
494
509
 
495
510
  ### Cache Tasks
496
511
 
@@ -0,0 +1,18 @@
1
+ # Contract: test-boundary (#3145)
2
+
3
+ ## Normative requirements
4
+
5
+ - ! `verify:test-boundary` MUST reject recognized test files under declared `sourceRoots` when they are not under `testRoots` and not allowlisted.
6
+ - ! Recognized patterns MUST include at least: Python `test_*.py` / `*_test.py`, C# `*Tests.cs` / `*Test.cs`, TypeScript/JavaScript `*.test.*` / `*.spec.*`, Go `*_test.go`.
7
+ - ! When `productionMayReferenceTestRoots` is false, production source and deployment/infra scripts MUST NOT reference `testRoots` or `fixtureRoots` path prefixes.
8
+ - ! Allow entries MUST support `kind: exception` and `kind: production-liveness` with recorded reason.
9
+ - ! Failures MUST identify path, violated boundary, and remediation.
10
+ - ! Defaults without authored policy MUST use warn-only discovery (`enforcementMode: warn`) for migration.
11
+ - ⊗ Infer safety solely because a path was listed in an active xBRIEF.
12
+
13
+ ## Surfaces
14
+
15
+ - Core: `packages/core/src/test-boundary/`
16
+ - CLI: `deft verify:test-boundary` / `task verify:test-boundary`
17
+ - Policy: `.deft/test-boundary.policy.json` or `plan.policy.testBoundary`
18
+ - Docs: `content/docs/test-boundary.md`
@@ -0,0 +1,64 @@
1
+ # Consumer check contract (`verify:consumer-check-contract`)
2
+
3
+ Refs: #3145 · Related: #3070 consumer gate integrity, #1519 check:consumer · Policy: #3189 coverageDebt / checkResume
4
+
5
+ ## Problem
6
+
7
+ A consumer could omit Directive enforcement gates from its `check` task and CI while local and CI success still looked green. Composition was not machine-checked.
8
+
9
+ ## Contract
10
+
11
+ `task verify:consumer-check-contract` requires these gates to be defined under `tasks/verify.yml` and composed into consumer/framework check aggregates:
12
+
13
+ - `verify:test-boundary`
14
+ - `verify:scope-provenance`
15
+ - `verify:consumer-check-contract`
16
+
17
+ It fails with a concrete repair path when definitions or explicit check deps omit them. CI workflows that neither invoke the gates nor a composing entrypoint (`task check` / `deft check`) produce **warnings** by default (migration).
18
+
19
+ ## Repair path
20
+
21
+ 1. Restore deposit Taskfiles: `deft update` (includes `tasks/verify.yml`)
22
+ 2. Ensure `check:consumer` / `check:framework-source` deps list the three gates (framework source already ships this wiring)
23
+ 3. Prefer CI that runs `task check` or `deft check` rather than a partial custom graph
24
+
25
+ ## Relation to #3070
26
+
27
+ `consumer-gate-integrity` proves Taskfile includes resolve. This gate proves the **required enforcement set** is present and composed — not merely that a random verify task exists.
28
+
29
+ ## Coverage-debt hatch and local check resume (#3189)
30
+
31
+ Release-born hatch and suite-stamp features must not expand to consumers as silent defaults. Project policy lives under `plan.policy` in PROJECT-DEFINITION:
32
+
33
+ | Field | Shape | Fail-closed when unset |
34
+ |---|---|---|
35
+ | `coverageDebt` | `status: unset \| decided`, `mode: off \| warn \| hatch`, `autoFile` (hatch only; default false) | mode off — no hatch soft-pass |
36
+ | `checkResume` | `status: unset \| decided`, `localStamp: off \| on`, `ciTrustsLocalStamp: false` (fixed v1) | localStamp off; **CI never trusts a laptop stamp** |
37
+
38
+ **Unset vs decided-off:** Unset keeps fail-closed *behavior* and still **nags** on interactive mutation session-start. Decided-off is quiet. Inspect with `deft policy:show --field=coverageDebt` and `--field=checkResume`. Doctor check `coverage-check-resume-policy` surfaces undecided as an **advisory skip** (never hard-fails doctor or `check:consumer`).
39
+
40
+ ### Skippable session nudge
41
+
42
+ On interactive cold or re-arm **mutation** session-start, when either field is unset:
43
+
44
+ - **Why:** long checks fail late or barely miss coverage; the project chooses fail-closed, warn, or hatch with a debt issue on **this** repo; local machines may resume a green suite at the same HEAD; CI must not trust a laptop stamp.
45
+ - **What:** one bundled choice — **Strict** (recommended), **Hatch-aware**, or **Later** (plus Discuss / Back per #1470).
46
+ - **Later** does **not** set `status=decided`; the next ritual nags again.
47
+ - **Stop nag** only after Strict / Hatch-aware (preset write) or **dismiss-with-reason** (visible on policy:show / doctor).
48
+ - Headless / CI / non-TTY: nudge is skipped (fail-open; never blocks).
49
+
50
+ ### Expansion gates (after decided)
51
+
52
+ | Feature | Expand to consumers? | Gate |
53
+ |---|---|---|
54
+ | Fast-before-slow gate ordering | Yes (universal UX) | No policy wait |
55
+ | Local suite stamp resume | When `checkResume.localStamp=on` | Local only; CI ignores |
56
+ | Coverage hatch / auto-file | When `coverageDebt.mode=hatch` (+ optional `autoFile`) | Ledger on **this** consumer repo |
57
+ | CI trusts local stamp | **Not v1** | Separate RFC |
58
+
59
+ ### Non-goals
60
+
61
+ - Silent default-on hatch for consumers.
62
+ - Auto-filing coverage-debt issues on **deftai/directive** from a consumer tree — the ledger is always **this** repo.
63
+ - USER.md as source of truth for ship bars (personal never weakens the project bar).
64
+ - Blocking headless CI on the nudge.
@@ -80,6 +80,12 @@ rm .deft-directive-disable
80
80
  # Start a NEW agent session
81
81
  ```
82
82
 
83
+ ## Agent self-serve ban under UAT (#3186)
84
+
85
+ Operators plant and remove this flag **outside** an agent session (or with a prior human-origin grant). Under **active UAT**, PreToolUse classifies Shell writes that create `.deft-directive-disable` (and permanent opt-out `.no-deft-directive`) as **settings** and **denies** them without a human grant — same posture as `authz:grant` (#3110). Agents must not self-serve the kill-switch to bypass Write / push / PR / merge gates.
86
+
87
+ Related: `policy:allow-bot-merge`, `policy:allow-direct-commits`, and `policy:disable-directive` (peers) are also settings under UAT and require a human grant.
88
+
83
89
  ## Non-goals (v1)
84
90
 
85
91
  - ⊗ Auto-delete `.deft/` or uninstall deposit
@@ -0,0 +1,173 @@
1
+ # Delivery-attempt circuit breaker (#3143)
2
+
3
+ Deterministic pre-dispatch gate and durable attempt ledger for autonomous
4
+ **delivery** and **operational-acceptance** loops.
5
+
6
+ This is the mechanical enforcement surface for the delivery/acceptance subset of
7
+ the dual-stop principle (#2442). Skill defaults (build / swarm / review-cycle)
8
+ remain behavioral; hosts and orchestrators that dispatch delivery workflows
9
+ MUST evaluate this gate before automatic retry or re-dispatch.
10
+
11
+ ## Module
12
+
13
+ | Path | Role |
14
+ |------|------|
15
+ | `packages/core/src/delivery-attempt/` | Library (types, fingerprint, material-delta, ledger, evaluate, handoff) |
16
+ | `@deftai/directive-core/delivery-attempt` | Package subpath export |
17
+ | `.deft/delivery-attempts/` | On-disk unit ledgers (project-local) |
18
+
19
+ ## Pre-dispatch decisions
20
+
21
+ `evaluatePreDispatch(ledger, input)` returns one of:
22
+
23
+ | Decision | Meaning |
24
+ |----------|---------|
25
+ | `ALLOW_FIRST_ATTEMPT` | No open failure identity for the unit |
26
+ | `ALLOW_TRANSIENT_RETRY` | Bounded retry after a transient (or under-threshold unknown) failure |
27
+ | `ALLOW_MATERIAL_PROGRESS` | Relevant material delta addresses the failing invariant |
28
+ | `ALLOW_OVERRIDE` / `ALLOW_RESUME` | Audited override or satisfied resume condition |
29
+ | `DENY_DUPLICATE_ACTIVE` | Queued/running attempt already exists for the unit |
30
+ | `BLOCK_NON_RETRYABLE` | Deterministic failure without progress |
31
+ | `BLOCK_NO_MATERIAL_PROGRESS` | Same failure class, no relevant delta |
32
+ | `BLOCK_REPEATED_UNKNOWN` | Identical unknown failures hit the threshold |
33
+ | `BLOCK_ATTEMPT_BUDGET` | Failed-dispatch budget for the phase exhausted |
34
+ | `BLOCK_ELAPSED_BUDGET` | Wall-clock budget exhausted |
35
+ | `BLOCK_TOOL_OR_TOKEN_BUDGET` | Tool-call (or host-token when telemetried) budget exhausted |
36
+
37
+ Once a **block** decision is emitted, automatic re-dispatch MUST stop until a
38
+ declared resume condition is satisfied or an audited operator override is
39
+ recorded. Persist the terminal handoff (`buildTerminalHandoff` /
40
+ `formatHandoffReport`) before the worker exits.
41
+
42
+ ## Unit key and durability
43
+
44
+ Logical unit: `scopeId + targetId + workflowId`.
45
+
46
+ Counters (`failedAttemptCount`, `sameFailureCounts`, elapsed/tool/token totals)
47
+ survive:
48
+
49
+ - worker replacement / takeover
50
+ - session restart and context compaction
51
+ - new source revisions (fingerprint counters do **not** reset)
52
+
53
+ Raw logs, credentials, and secret-bearing payloads MUST NOT be stored in the
54
+ ledger. Failure fingerprints redact volatile ids, paths, timestamps, and
55
+ secret-like values (`computeFailureFingerprint`).
56
+
57
+ ## Material progress
58
+
59
+ Material progress means verifiable state changed in a way that can resolve or
60
+ advance beyond the current failure (code/config/evidence/external-state/stage
61
+ that **addresses** the failing invariant).
62
+
63
+ Not material progress by themselves:
64
+
65
+ - new revision identifiers alone
66
+ - repeating the same dispatch
67
+ - restating analysis
68
+ - replacing the worker
69
+ - compaction / session restart
70
+ - evidence bound to an intermediate revision when evaluating a later revision
71
+
72
+ ## Safe defaults (`DEFAULT_DELIVERY_BUDGET_POLICY`)
73
+
74
+ | Knob | Default |
75
+ |------|---------|
76
+ | max active (queued+running) | 1 |
77
+ | max automatic transient retries | 1 |
78
+ | identical unknown without progress → block | 2 |
79
+ | failed dispatches per phase → block | 3 |
80
+ | max elapsed seconds | 3600 |
81
+ | max tool calls | 500 |
82
+ | max host tokens | null (enforce only when host exposes usage **and** policy sets a cap) |
83
+
84
+ Missing host token telemetry does **not** disable the circuit breaker — elapsed
85
+ and tool-call budgets still apply.
86
+
87
+ ## Operator override
88
+
89
+ `recordOperatorOverride` requires actor, rationale, timestamp, bounded
90
+ `allowedAttempts`, and optional expiry. Overrides do **not** erase attempt
91
+ history.
92
+
93
+ ## Skill routing
94
+
95
+ | Surface | Role |
96
+ |---------|------|
97
+ | `main.md` Dual Stop Rule (#2442) | Principle; points here for delivery/acceptance |
98
+ | build / swarm / review-cycle skills | Behavioral dual-stop defaults; point here for mechanical gate |
99
+ | swarm `core-ops` / `core-phase-4` | Prompt + monitor envelopes; do not invent a second ledger |
100
+
101
+ ## Typical call shape
102
+
103
+ Use the **locked disk APIs** for concurrent-safe begin/complete. Do not evaluate
104
+ on a stale in-memory snapshot and then `saveUnitLedger` without the unit lock.
105
+
106
+ ```ts
107
+ import {
108
+ beginAttemptOnDisk,
109
+ completeAttemptOnDisk,
110
+ buildFailureInfo,
111
+ } from "@deftai/directive-core/delivery-attempt";
112
+
113
+ // beginAttemptOnDisk: exclusive lock → reload → evaluatePreDispatch → begin → save
114
+ let attempt;
115
+ try {
116
+ const begun = beginAttemptOnDisk(projectRoot, {
117
+ scopeId,
118
+ targetId,
119
+ workflowId,
120
+ sourceRevision,
121
+ trigger: "automatic",
122
+ anticipatedFailure: lastFailure,
123
+ materialDelta: claims,
124
+ });
125
+ attempt = begun.attempt;
126
+ } catch (err) {
127
+ // DENY_*/BLOCK_* — handoff already persisted when blocked
128
+ return;
129
+ }
130
+
131
+ // ... run workflow ...
132
+
133
+ // completeAttemptOnDisk: exclusive lock → reload → complete → save
134
+ const closed = completeAttemptOnDisk(projectRoot, {
135
+ scopeId,
136
+ targetId,
137
+ workflowId,
138
+ attemptId: attempt.attemptId,
139
+ status: "failed",
140
+ failure: buildFailureInfo({ stage, code, message, retryability }),
141
+ });
142
+ ```
143
+
144
+ Pure in-memory helpers (`evaluatePreDispatch`, `beginAttempt`, `completeAttempt`)
145
+ remain for tests and single-threaded hosts. Multi-worker orchestration MUST use
146
+ `beginAttemptOnDisk` / `completeAttemptOnDisk` (or `withUnitLock` around an
147
+ equivalent sequence). Abandoned unit locks are reclaimed **only** when the owner
148
+ PID is dead or the lock record is corrupt/unreadable. A live owner PID is never
149
+ time-reclaimed (including long critical sections and event-loop stalls). Reclaim
150
+ is serialized via an exclusive `*.lock.reclaim` ticket so concurrent reclaimers
151
+ cannot unlink a live replacement lock. If a lock remains stuck after process
152
+ death with PID reuse (or a hung live holder), delete the matching `.lock` /
153
+ `.lock.reclaim` files under `.deft/delivery-attempts/` manually.
154
+
155
+ Ledger load is **fail-closed on corruption**: a present but invalid ledger file
156
+ throws (does not create an empty unit). Only a truly missing file creates a new
157
+ empty ledger. Operators must repair or remove a corrupt file deliberately before
158
+ dispatch can resume for that unit.
159
+
160
+ ## Observability
161
+
162
+ Every evaluation emits a structured `PreDispatchDecisionEvent`
163
+ (`decision`, `reasonCode`, retryability, fingerprint, counters, material-delta
164
+ class, resume condition, override id). Aggregate metrics can count duplicate
165
+ denies, deterministic blocks, and budget savings from early halt.
166
+
167
+ ## Non-goals
168
+
169
+ - Weakening validation, review, or deploy safety gates
170
+ - Treating every different downstream failure as the same failure
171
+ - Preventing deliberate audited overrides
172
+ - Provider-specific CI/CD lock-in
173
+ - Prompt-only thrashing control (use dual-stop skill defaults for that class)
@@ -56,7 +56,7 @@ Bodies stay **thin** (L5): frontmatter + short dispatch pointer to the same cont
56
56
  4. Opt-out: `plan.policy.openClawProductCommands: false` — removes **managed** L2 thin skills only; preserves consumer custom skills at the same slug.
57
57
  5. After deposit: **restart the OpenClaw gateway or start a new session** so `available_skills` refreshes.
58
58
 
59
- Always-pin skills (`deft-directive-build`, `pre-pr`, `review-cycle`, `swarm`) remain a **different** surface from L2 product commands (`/deft:directive:run:interview`, `/deft:continue`, …).
59
+ Always-pin skills (`deft-directive-build`, `pre-pr`, `review-cycle`, `swarm`) remain a **different** surface from L2 product commands (`/deft:directive:run:interview`, `/deft:continue`, …). Soft post-compact re-bind (`deft-directive-post-compact-rebind`, #3171) is a third surface — see § Soft post-compact AGENTS re-bind below.
60
60
 
61
61
  Inspect policy:
62
62
 
@@ -66,6 +66,41 @@ deft policy:show --field=openClawProductCommands
66
66
 
67
67
  ---
68
68
 
69
+ ## Soft post-compact AGENTS re-bind (#3171 / #2769)
70
+
71
+ OpenClaw is a **Family-2** session host. Soft AGENTS re-bind after compaction / long-session amnesia is **required** on OpenClaw and is **not** claimed via Cursor/Claude/Grok file-host `PreCompact` hooks alone.
72
+
73
+ | Surface | OpenClaw posture |
74
+ |---------|------------------|
75
+ | **Hard** compact re-arm (file-host PreToolUse stale → deny writes) | **Not** provided by file-host compact hooks on OpenClaw. Mutation still requires `session:start` / `session:ready` / gated ritual via CLI/skills before gated writes. |
76
+ | **Soft** AGENTS re-bind | **Required** durable workspace skill from the **shared checklist SoT** (`packages/core/src/session/compact-ritual.ts`). |
77
+
78
+ ### Checklist obligations (same SoT as file hosts)
79
+
80
+ 1. Re-read managed `AGENTS.md` session routing (#2176) — summary ≠ SoT.
81
+ 2. Confirm-what-you-learned (brief) in the user-visible reply.
82
+ 3. Deposit integrity: `deft` on PATH ≠ healthy `.deft/core` deposit.
83
+ 4. Summary/runbook (demo DBs, “start the app”) are hypotheses — re-verify PROJECT-DEFINITION / USER.md / local config.
84
+ 5. Operational-ask trap: “open/start/run the app” is still session-routed (#3161).
85
+ 6. Read-only → soft only; mutation → soft **plus** hard re-arm where supported. Soft **never** authorizes skipping the mutation ritual for writes.
86
+
87
+ ### Deposit / amnesia boundary
88
+
89
+ | Step | Action |
90
+ |------|--------|
91
+ | Detect / fix | `deft doctor` warns when OpenClaw is detected and the managed skill is missing/stale; `deft doctor --fix` deposits it (multi-seat: `--openclaw-all-agents`) |
92
+ | init / update | Deposits when OpenClaw signals are present (fail-closed otherwise) |
93
+ | Skill id | `deft-directive-post-compact-rebind` under the OpenClaw workspace skills root |
94
+ | After deposit | **Restart the OpenClaw gateway or start a new session** so skills reload |
95
+ | Trigger | Session start / resume, gateway restart, long-session amnesia, operational asks after summary resume |
96
+
97
+ ⊗ Claim OpenClaw soft coverage from file-host hook deposits alone.
98
+ ⊗ Treat “pins present” as “session ritual completed.”
99
+
100
+ Shared dual-surface + five-host matrix: [commands.md](../commands.md) § Agent-host hooks → Compact re-arm + soft AGENTS re-bind.
101
+
102
+ ---
103
+
69
104
  ## Mental model (host class)
70
105
 
71
106
  | Host | Host-native background spawn (typical) | Directive review-monitor role |
@@ -0,0 +1,57 @@
1
+ # Operator-log hygiene checklist (#1940)
2
+
3
+ Copy-paste block for **story acceptance criteria** and **probe locked
4
+ decisions**. Full pattern:
5
+ [`patterns/operator-log-hygiene.md`](../patterns/operator-log-hygiene.md).
6
+
7
+ Legend (RFC2119): `!`=MUST, `~`=SHOULD, `⊗`=MUST NOT, `?`=MAY.
8
+
9
+ **Load when:** building operator-facing services, adding WARN/ERROR paths
10
+ operators triage, multi-process workers, or probing logging decisions.
11
+
12
+ ## Story AC / probe locked decisions (copy-paste)
13
+
14
+ Use as-is in scope xBRIEF acceptance, probe locked decisions, or PR
15
+ checklist. Mark N/A only with a one-line reason.
16
+
17
+ ```markdown
18
+ ### Operator-log hygiene (#1940)
19
+
20
+ Legend: ! = MUST, ~ = SHOULD, ? = MAY (from patterns/operator-log-hygiene.md)
21
+
22
+ - [ ] ! Terminal / completion events on **all** exit paths (success, skip,
23
+ timeout, supersede, cancel, failure) — not happy path only
24
+ - [ ] ! Correlation IDs for multi-process / pool designs (job id, slot,
25
+ phase, parent id as applicable)
26
+ - [ ] ! Infrastructure paths (rotation, flush-before-exit, IPC handoff,
27
+ boot supervision) fail-open where possible and emit structured
28
+ events when they degrade
29
+ - [ ] ~ Operator-visible WARN/ERROR use a stable, queryable shape
30
+ (consumer-owned fields; e.g. stable event id + short operator
31
+ summary) — not ticket numbers alone
32
+ - [ ] ~ Operator glossary / plain-English docs updated in the **same PR**
33
+ when operator-facing log lines change
34
+ - [ ] ? Optional: wire consumer-owned validator into *your* check aggregate
35
+ (see docs/operator-log-hygiene-consumer-pack-stub.md) — not core default
36
+ - [ ] Explicit non-goals respected: no assumption that core `deft check`
37
+ enforces this; log shape stays consumer-owned
38
+ ```
39
+
40
+ ## Agent rules when applying the checklist
41
+
42
+ - ! MUST run this checklist before claiming "logging done" on an
43
+ operator-visible lifecycle path
44
+ - ! MUST keep log field names and schemas **project-owned** unless the
45
+ consumer already defined them
46
+ - ~ SHOULD attach the checklist under probe locked decisions when the plan
47
+ introduces or changes operator-facing logs
48
+ - ⊗ MUST NOT invent a framework-wide required field set (`operatorSummary`,
49
+ etc.) from this checklist alone
50
+ - ⊗ MUST NOT treat Product Insights (#2603) or LLM telemetry (#481) as
51
+ substitutes for operator-log hygiene
52
+
53
+ ## Related
54
+
55
+ - Pattern: `content/patterns/operator-log-hygiene.md`
56
+ - Optional consumer pack stub: `content/docs/operator-log-hygiene-consumer-pack-stub.md`
57
+ - External case study (reference only): deftai/slizard operator-log hygiene docs and `operator-log:validate` — do not import schema into core
@@ -0,0 +1,75 @@
1
+ # Operator-log hygiene — optional consumer pack stub (#1940)
2
+
3
+ Skeleton for **consumer projects** that want a ship-gate for operator-facing
4
+ logs. Wire this into *your* check aggregate only if you opt in.
5
+
6
+ Full pattern: [`patterns/operator-log-hygiene.md`](../patterns/operator-log-hygiene.md).
7
+ Checklist: [`operator-log-hygiene-checklist.md`](./operator-log-hygiene-checklist.md).
8
+
9
+ ## Settled boundaries
10
+
11
+ | Topic | Rule |
12
+ |-------|------|
13
+ | Default-on | **Off.** Directive core does not enable this for all services. |
14
+ | Schema | **Consumer-owned.** You define fields and glossary path. |
15
+ | Framework `deft check` | **Does not** hard-fail consumers who never opted in. |
16
+ | External refs | SLizard `task operator-log:validate` is a **reference** only. |
17
+
18
+ ## Suggested Taskfile target name
19
+
20
+ Prefer a project-local name so it does not imply framework ownership:
21
+
22
+ ```yaml
23
+ # tasks/observability.yml (consumer-owned example — not shipped by core)
24
+ version: "3"
25
+
26
+ tasks:
27
+ operator-log:validate:
28
+ desc: Validate operator-facing log shape / glossary (consumer-owned)
29
+ cmds:
30
+ - echo "Implement inventory + schema checks for YOUR log contract"
31
+ # - node scripts/validate-operator-log.mjs --strict
32
+ ```
33
+
34
+ Optional aliases consumers sometimes use:
35
+
36
+ - `observability:validate`
37
+ - `ops-log:check`
38
+
39
+ Pick one name and keep it stable in your repo.
40
+
41
+ ## Validator skeleton (comments only)
42
+
43
+ ```js
44
+ // scripts/validate-operator-log.mjs (consumer-owned skeleton)
45
+ //
46
+ // 1. Inventory: find operator-facing log call sites (WARN/ERROR + terminal events).
47
+ // 2. Schema: load YOUR glossary / field contract (path from project config).
48
+ // 3. Strict mode: fail if new events lack required consumer fields.
49
+ // 4. Exit 0 when clean; exit 1 with actionable paths when not.
50
+ //
51
+ // ⊗ Do not import SLizard glossary JSON as universal SoT.
52
+ // ⊗ Do not expect @deftai/directive to ship or enforce this script.
53
+ //
54
+ // Reference shape (external): deftai/slizard task operator-log:validate
55
+ ```
56
+
57
+ ## Wire into *your* check (optional)
58
+
59
+ ```yaml
60
+ # In the consumer Taskfile check aggregate — only if you want hard-fail
61
+ tasks:
62
+ check:
63
+ deps:
64
+ - operator-log:validate
65
+ # ...other consumer gates...
66
+ ```
67
+
68
+ - ! MUST document the gate as **project policy** when enabled
69
+ - ⊗ MUST NOT claim framework `deft check` mandates this target by default
70
+ - ? MAY keep the script warn-only until glossary coverage is good enough
71
+
72
+ ## Related
73
+
74
+ - #1940 thin v1 — content + checklist + this stub
75
+ - Pattern non-goals: no `plan.observability` core schema, no default-on
@@ -0,0 +1,54 @@
1
+ # Approved-scope provenance (`verify:scope-provenance`)
2
+
3
+ Refs: #3145 · Related: #1310, #2944 human-origin grants, #516 file scope
4
+
5
+ ## Problem
6
+
7
+ An implementation PR could edit its own active xBRIEF to add new paths, after which one-way forward-coverage still passed. The modified xBRIEF became its own authorization source.
8
+
9
+ ## Contract
10
+
11
+ At activation or operator approval, record an immutable **approved-scope digest** under:
12
+
13
+ ```text
14
+ .deft/approved-scope/<plan-id>.json
15
+ ```
16
+
17
+ Shape:
18
+
19
+ ```json
20
+ {
21
+ "schemaVersion": 1,
22
+ "xbriefRelPath": "xbrief/active/….xbrief.json",
23
+ "planId": "…",
24
+ "approvedAt": "2026-08-06T00:00:00Z",
25
+ "fileScope": ["packages/core/src/foo.ts"],
26
+ "fileScopeDigest": "<sha256 of sorted paths>",
27
+ "humanApproval": {
28
+ "kind": "operator",
29
+ "actor": "scott",
30
+ "mintedAt": "2026-08-06T00:00:00Z"
31
+ }
32
+ }
33
+ ```
34
+
35
+ `task verify:scope-provenance` compares the live active xBRIEF `plan.metadata.swarm.file_scope` to the digest when that xBRIEF is modified in the current change set.
36
+
37
+ | Outcome | Behavior |
38
+ | --- | --- |
39
+ | No expansion | Pass |
40
+ | Expansion + renewed human stamp / re-recorded matching digest | Pass |
41
+ | Expansion without renewal | **Fail** — self-authorizing scope |
42
+ | Modified active xBRIEF, no digest yet | **Warn** by default; `--enforce` fails closed |
43
+
44
+ Agent-shaped stamps (`kind: agent`, `actor: agent:…`) never count as renewal.
45
+
46
+ ## Migration path
47
+
48
+ 1. Ship gate in warn mode (missing digests do not fail)
49
+ 2. Start recording digests on activation / promote
50
+ 3. Enable `--enforce` or project policy when ready
51
+
52
+ ## Remediation
53
+
54
+ Re-record the approved-scope file after human review of the expanded `file_scope`. Editing the xBRIEF alone does not authorize new implementation paths.