@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.
- package/.agents/skills/deft-directive-portfolio-priority/SKILL.md +11 -0
- package/Taskfile.yml +6 -0
- package/UPGRADING.md +9 -6
- package/commands.md +17 -2
- package/contracts/test-boundary.md +18 -0
- package/docs/consumer-check-contract.md +64 -0
- package/docs/deft-directive-disable.md +6 -0
- package/docs/delivery-attempt.md +173 -0
- package/docs/openclaw-agent-host.md +36 -1
- package/docs/operator-log-hygiene-checklist.md +57 -0
- package/docs/operator-log-hygiene-consumer-pack-stub.md +75 -0
- package/docs/scope-provenance.md +54 -0
- package/docs/test-boundary.md +43 -0
- package/main.md +46 -0
- package/meta/philosophy.md +10 -0
- package/package.json +1 -1
- package/packs/patterns/patterns-pack-0.1.json +10 -0
- package/packs/skills/skills-pack-0.1.json +22 -5
- package/patterns/operator-log-hygiene.md +130 -0
- package/scm/github.md +26 -0
- package/skills/deft-directive-article-review/SKILL.md +17 -6
- package/skills/deft-directive-build/SKILL.md +41 -0
- package/skills/deft-directive-portfolio-priority/SKILL.md +144 -0
- package/skills/deft-directive-release/SKILL.md +22 -5
- package/skills/deft-directive-review-cycle/SKILL.md +150 -0
- package/skills/deft-directive-swarm/SKILL.md +14 -0
- package/skills/deft-directive-swarm/references/core-ops.md +14 -2
- package/skills/deft-directive-swarm/references/core-phase-0.md +34 -1
- package/skills/deft-directive-swarm/references/core-phase-3.md +6 -0
- package/skills/deft-directive-swarm/references/core-phase-4.md +21 -2
- package/skills/deft-directive-swarm/references/core-phase-5-6.md +17 -0
- package/skills/deft-directive-swarm/references/host-openclaw.md +4 -0
- package/tasks/engine-invoke.cjs +22 -17
- package/tasks/engine-invoke.test.cjs +30 -0
- package/tasks/verify.yml +30 -0
- package/templates/agent-prompt-preamble.md +8 -0
- package/templates/agents-entry.md +10 -0
- 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`
|
|
272
|
-
|
|
|
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
|
|
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.
|