@deftai/directive-runtime 0.129.7 → 0.129.8

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 (90) hide show
  1. package/Taskfile.yml +9 -3
  2. package/commands.md +4 -1
  3. package/package.json +1 -1
  4. package/scm/github.md +5 -0
  5. package/skills/deft-directive-swarm/references/host-claude-code.md +11 -1
  6. package/vendor/directive-content/Taskfile.yml +9 -3
  7. package/vendor/directive-content/commands.md +4 -1
  8. package/vendor/directive-content/scm/github.md +5 -0
  9. package/vendor/directive-content/skills/deft-directive-swarm/references/host-claude-code.md +11 -1
  10. package/vendor/directive-core/dist/.tsbuildinfo +1 -1
  11. package/vendor/directive-core/dist/check/context.d.ts.map +1 -1
  12. package/vendor/directive-core/dist/check/context.js +3 -31
  13. package/vendor/directive-core/dist/check/context.js.map +1 -1
  14. package/vendor/directive-core/dist/check/gate-lists.d.ts.map +1 -1
  15. package/vendor/directive-core/dist/check/gate-lists.js +4 -32
  16. package/vendor/directive-core/dist/check/gate-lists.js.map +1 -1
  17. package/vendor/directive-core/dist/check/walk-test-files.d.ts +3 -0
  18. package/vendor/directive-core/dist/check/walk-test-files.d.ts.map +1 -0
  19. package/vendor/directive-core/dist/check/walk-test-files.js +67 -0
  20. package/vendor/directive-core/dist/check/walk-test-files.js.map +1 -0
  21. package/vendor/directive-core/dist/hooks/dispatcher.d.ts +6 -0
  22. package/vendor/directive-core/dist/hooks/dispatcher.d.ts.map +1 -1
  23. package/vendor/directive-core/dist/hooks/dispatcher.js +64 -6
  24. package/vendor/directive-core/dist/hooks/dispatcher.js.map +1 -1
  25. package/vendor/directive-core/dist/hooks/scope.d.ts +54 -0
  26. package/vendor/directive-core/dist/hooks/scope.d.ts.map +1 -1
  27. package/vendor/directive-core/dist/hooks/scope.js +83 -2
  28. package/vendor/directive-core/dist/hooks/scope.js.map +1 -1
  29. package/vendor/directive-core/dist/intake/reconcile-issues.d.ts +33 -1
  30. package/vendor/directive-core/dist/intake/reconcile-issues.d.ts.map +1 -1
  31. package/vendor/directive-core/dist/intake/reconcile-issues.js +288 -12
  32. package/vendor/directive-core/dist/intake/reconcile-issues.js.map +1 -1
  33. package/vendor/directive-core/dist/intake/thin-brief.d.ts +78 -0
  34. package/vendor/directive-core/dist/intake/thin-brief.d.ts.map +1 -0
  35. package/vendor/directive-core/dist/intake/thin-brief.js +224 -0
  36. package/vendor/directive-core/dist/intake/thin-brief.js.map +1 -0
  37. package/vendor/directive-core/dist/policy/ceremony-dial.d.ts.map +1 -1
  38. package/vendor/directive-core/dist/policy/ceremony-dial.js +2 -1
  39. package/vendor/directive-core/dist/policy/ceremony-dial.js.map +1 -1
  40. package/vendor/directive-core/dist/policy/small-change-lane.d.ts +193 -0
  41. package/vendor/directive-core/dist/policy/small-change-lane.d.ts.map +1 -0
  42. package/vendor/directive-core/dist/policy/small-change-lane.js +690 -0
  43. package/vendor/directive-core/dist/policy/small-change-lane.js.map +1 -0
  44. package/vendor/directive-core/dist/preflight/evaluate.d.ts +3 -0
  45. package/vendor/directive-core/dist/preflight/evaluate.d.ts.map +1 -1
  46. package/vendor/directive-core/dist/preflight/evaluate.js +15 -0
  47. package/vendor/directive-core/dist/preflight/evaluate.js.map +1 -1
  48. package/vendor/directive-core/dist/product-first-done-gate/evaluate.d.ts +6 -0
  49. package/vendor/directive-core/dist/product-first-done-gate/evaluate.d.ts.map +1 -1
  50. package/vendor/directive-core/dist/product-first-done-gate/evaluate.js +26 -0
  51. package/vendor/directive-core/dist/product-first-done-gate/evaluate.js.map +1 -1
  52. package/vendor/directive-core/dist/scope/decomposed-refs.d.ts +7 -0
  53. package/vendor/directive-core/dist/scope/decomposed-refs.d.ts.map +1 -1
  54. package/vendor/directive-core/dist/scope/decomposed-refs.js +27 -10
  55. package/vendor/directive-core/dist/scope/decomposed-refs.js.map +1 -1
  56. package/vendor/directive-core/dist/scope/delivery-evidence.d.ts +18 -2
  57. package/vendor/directive-core/dist/scope/delivery-evidence.d.ts.map +1 -1
  58. package/vendor/directive-core/dist/scope/delivery-evidence.js +30 -5
  59. package/vendor/directive-core/dist/scope/delivery-evidence.js.map +1 -1
  60. package/vendor/directive-core/dist/scope/transition.d.ts +3 -0
  61. package/vendor/directive-core/dist/scope/transition.d.ts.map +1 -1
  62. package/vendor/directive-core/dist/scope/transition.js +43 -3
  63. package/vendor/directive-core/dist/scope/transition.js.map +1 -1
  64. package/vendor/directive-core/dist/scope-provenance/base-fence.d.ts +2 -1
  65. package/vendor/directive-core/dist/scope-provenance/base-fence.d.ts.map +1 -1
  66. package/vendor/directive-core/dist/scope-provenance/base-fence.js +9 -1
  67. package/vendor/directive-core/dist/scope-provenance/base-fence.js.map +1 -1
  68. package/vendor/directive-core/dist/swarm/finalize-cohort.d.ts +20 -1
  69. package/vendor/directive-core/dist/swarm/finalize-cohort.d.ts.map +1 -1
  70. package/vendor/directive-core/dist/swarm/finalize-cohort.js +78 -33
  71. package/vendor/directive-core/dist/swarm/finalize-cohort.js.map +1 -1
  72. package/vendor/directive-core/dist/swarm/finalize-owed.d.ts +18 -3
  73. package/vendor/directive-core/dist/swarm/finalize-owed.d.ts.map +1 -1
  74. package/vendor/directive-core/dist/swarm/finalize-owed.js +139 -32
  75. package/vendor/directive-core/dist/swarm/finalize-owed.js.map +1 -1
  76. package/vendor/directive-core/dist/swarm/launch.d.ts.map +1 -1
  77. package/vendor/directive-core/dist/swarm/launch.js +4 -8
  78. package/vendor/directive-core/dist/swarm/launch.js.map +1 -1
  79. package/vendor/directive-core/dist/swarm/worker-auth-assignment.d.ts +7 -0
  80. package/vendor/directive-core/dist/swarm/worker-auth-assignment.d.ts.map +1 -1
  81. package/vendor/directive-core/dist/swarm/worker-auth-assignment.js +16 -1
  82. package/vendor/directive-core/dist/swarm/worker-auth-assignment.js.map +1 -1
  83. package/vendor/directive-core/dist/task-surface/index.d.ts.map +1 -1
  84. package/vendor/directive-core/dist/task-surface/index.js +41 -0
  85. package/vendor/directive-core/dist/task-surface/index.js.map +1 -1
  86. package/vendor/directive-core/dist/vbrief-reconcile/types.d.ts +5 -1
  87. package/vendor/directive-core/dist/vbrief-reconcile/types.d.ts.map +1 -1
  88. package/vendor/directive-core/dist/vbrief-reconcile/umbrellas.d.ts.map +1 -1
  89. package/vendor/directive-core/dist/vbrief-reconcile/umbrellas.js +19 -7
  90. package/vendor/directive-core/dist/vbrief-reconcile/umbrellas.js.map +1 -1
package/Taskfile.yml CHANGED
@@ -816,7 +816,9 @@ tasks:
816
816
  cmds:
817
817
  - task: engine:invoke
818
818
  vars:
819
- ENGINE_CMD: 'release-publish {{.CLI_ARGS}}'
819
+ # #5805 / #5942: the pin's default project root is its own package dir, so pass the
820
+ # operator root explicitly (an operator --project-root in CLI_ARGS still wins).
821
+ ENGINE_CMD: 'release-publish --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
820
822
 
821
823
  release:rollback:
822
824
  desc: "State-aware release unwind (#716) -- task release:rollback -- <version> [--dry-run] [--allow-low-downloads N] [--allow-data-loss] [--force-strict-0]"
@@ -825,7 +827,9 @@ tasks:
825
827
  cmds:
826
828
  - task: engine:invoke
827
829
  vars:
828
- ENGINE_CMD: 'release-rollback {{.CLI_ARGS}}'
830
+ # #5805 / #5942: the pin's default project root is its own package dir, so pass the
831
+ # operator root explicitly (an operator --project-root in CLI_ARGS still wins).
832
+ ENGINE_CMD: 'release-rollback --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
829
833
 
830
834
  release:e2e:
831
835
  desc: "End-to-end release rehearsal against an auto-created temp repo (#716, #2572 keep+report default) -- task release:e2e [-- --dry-run] [--owner OWNER] [--destroy-repo]"
@@ -834,7 +838,9 @@ tasks:
834
838
  cmds:
835
839
  - task: engine:invoke
836
840
  vars:
837
- ENGINE_CMD: 'release-e2e {{.CLI_ARGS}}'
841
+ # #5805 / #5942: the pin's default project root is its own package dir, so pass the
842
+ # operator root explicitly (an operator --project-root in CLI_ARGS still wins).
843
+ ENGINE_CMD: 'release-e2e --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
838
844
 
839
845
  release:wait-npm:
840
846
  desc: "Phase 7 wait until both public OVPR packages (@deftai/directive + @deftai/directive-runtime) list the cut version (#4267 / #5490) -- task release:wait-npm -- <version>"
package/commands.md CHANGED
@@ -149,7 +149,8 @@ Common commands:
149
149
  - Bare `evidence` / `disposition` keys are **not** valid (#1620 / Option B #3305). They fail `verify:vbrief-conformance` and are treated as missing by `scope:complete` (no dual-read). Migrate bare keys or narrative-only `Result`/`Verification` workarounds to the namespaced fields above while items are still non-terminal.
150
150
  - Already-terminal items (`completed`/`failed`/`cancelled`/…) are not re-checked for typed evidence; pre-marking items complete to skip the gate is unsupported for the typed path.
151
151
  - `merge`/`review` alone cannot satisfy smoke/UAT/deploy/observed_behavior criteria (title/Acceptance text or explicit axis).
152
- - **Delivery identity (#5710):** with an issue origin, the PR must be associated with the issue as of `merged_at` by one of: (a) a unique sole `deft-story: N` mark in the merge-time PR body (PRs that change only briefs and `CHANGELOG.md` are excluded and never count), (b) a closing keyword (`Closes #N`, `owner/repo#N`, or the issue URL) in the merge-time body, or (c) a Connected issue link at `merged_at`. Brief-in-PR-diff still counts. A mark, keyword or link added after merge does not count, and current `closingIssuesReferences` alone is not enough. Basis (a) scans every merged PR within 20 minutes, `graphql.remaining` ≥ 200 and REST core ≥ 100; any gap refuses. With no issue origin, stamp `plan.metadata.productPullRequest` and complete with `--pr <that number> --merge-commit <sha>`; the repository is the `origin` remote. `--non-delivery` refuses when the stamped PR is merged, and refuses when its merge state cannot be read. `xbrief:preflight` prints one note for a code-bearing brief with no issue origin.
152
+ - **Delivery identity (#5710):** with an issue origin, the PR must be associated with the issue as of `merged_at` by one of: (a) a unique sole `deft-story: N` mark in the merge-time PR body (PRs that change only lifecycle briefs, `CHANGELOG.md` and the spec-drift ledger are excluded and never count), (b) a closing keyword (`Closes #N`, `owner/repo#N`, or the issue URL) in the merge-time body, or (c) a Connected issue link at `merged_at`. Brief-in-PR-diff still counts. A mark, keyword or link added after merge does not count, and current `closingIssuesReferences` alone is not enough. Basis (a) scans every merged PR within 20 minutes, `graphql.remaining` ≥ 200 and REST core ≥ 100; any gap refuses. With no issue origin, stamp `plan.metadata.productPullRequest` and complete with `--pr <that number> --merge-commit <sha>`; the repository is the `origin` remote. `--non-delivery` refuses when the stamped PR is merged, and refuses when its merge state cannot be read. `xbrief:preflight` prints one note for a code-bearing brief with no issue origin.
153
+ - **Lifecycle completion (#680):** completion admission uses the merge-time bases above; there is no separate keyword-only refuse. `swarm:finalize-owed` also lists an active issue-less brief with a stamped `productPullRequest` (shown as `pr #P`, no issue number, no origin-issue check or origin-close); briefs that share a product PR finalize together under one claim. In a batched `swarm:finalize-cohort`, a refused `deft-story` mark is not an error: that story stays pending, unstamped and unswept (`refused_marks`, exit 3 incomplete), and the other stories stamp, sweep, commit and land. A failed changed-file lookup and real delivery errors still fail the batch. `scope:complete` writes the spec-drift ledger as verb output; finalize commits it with the completed briefs, and scope-provenance membership admits exactly `xbrief/.audit/spec-drift-ledger.json` only when the whole change set is a completion move. `verify:changelog-unreleased` needs no new `[Unreleased]` line when the change set versus merge-base (`git diff --name-only --no-renames`) is non-empty and only lifecycle briefs, `CHANGELOG.md` and that ledger, so lifecycle verbs write no CHANGELOG line. Product changes and an empty change set still need one.
153
154
  - `task scope:fail -- xbrief/active/<file>.xbrief.json` -- mark running work failed when the scope cannot complete.
154
155
  - `task scope:cancel -- <path>` -- move a scope to `cancelled/`.
155
156
  - `task scope:restore`, `task scope:block`, `task scope:unblock`, `task scope:demote`, and `task scope:undo:*` -- repair or reverse lifecycle transitions.
@@ -182,6 +183,8 @@ The implementation gate succeeds only for active scope xBRIEFs with `plan.status
182
183
 
183
184
  **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.
184
185
 
186
+ **Small-change lane (#6204):** Under the `rapid` ceremony dial, a scope with stated acceptance commands may use a thin brief: title, issue ref, `file_scope` and acceptance commands only (`emitThinBrief`, `packages/core/src/intake/thin-brief.ts`). The bound defaults to 5 production files and 500 changed lines (added plus deleted, tests included; briefs and CHANGELOG excluded). `plan.policy.ceremonyDial.smallChangeLane` (`maxProductionFiles`, `maxChangedLines`) overrides each field; an invalid value refuses. `scope:promote`, `scope:activate`, `xbrief:preflight`, `verify:ac` and `scope:complete` admit the thin shape, and each one remeasures the cumulative product diff (git, against the lane-admit base in `plan.metadata["x-directive/smallChangeLane"]`; at `scope:complete`, the delivered merge commit against its first parent). A crossed bound, a public-surface change (manifest, entry, task file or export line), an unknown public surface, or a depth other than `rapid` refuses. A crossed bound or public-surface change is recorded on the brief (lane state `crossed`), so every later retry refuses even if the diff shrinks. The public-surface check reads export statements with the TypeScript parser, so a change inside a multi-line export list or exported signature counts. The one remediation is lane exit: convert the scope to the full shape (`escalateThinBriefToFullShape`), which keeps scope identity and acceptance evidence. Raising the dial (#3319) does not clear the refusal. One-PR delivery is not part of this lane; Path B brief-first stays lawful (#6203 / #680).
187
+
185
188
  ```mermaid
186
189
  flowchart TD
187
190
  Candidate["Scope xBRIEF exists"] --> Promote{"In proposed?"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deftai/directive-runtime",
3
- "version": "0.129.7",
3
+ "version": "0.129.8",
4
4
  "description": "Directive runtime — pinned product commands, hooks, content, and engine.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://deftai.github.io/directive/",
package/scm/github.md CHANGED
@@ -722,6 +722,11 @@ Up-to-date-required branch protection plus a required `Merge gate (task check)`
722
722
 
723
723
  ⊗ Mutate GitHub `mergeable_state` to encode semantic/policy readiness — forge enrollment + local probe are the dispositioned alternatives (#4888 Prefer-A Bound Reject E).
724
724
 
725
+ ### Lifecycle PRs: CHANGELOG and spec-drift ledger (#680)
726
+
727
+ - `verify:changelog-unreleased` skips the new-entry compare when the change set versus merge-base (`git diff --name-only --no-renames`) is non-empty and every path is a lifecycle brief (`xbrief|vbrief/<lifecycle>/`), `CHANGELOG.md`, or `xbrief/.audit/spec-drift-ledger.json`. Activation and completion PRs need no operator CHANGELOG line. Product changes and an empty change set keep the requirement.
728
+ - `scope:complete` writes the spec-drift ledger; `swarm:finalize-cohort` commits it with the completed briefs. Membership admits exactly that ledger path only when the whole change set is a completion move. The verbs own these writes, so agents do not hand-write CHANGELOG or ledger lines on a lifecycle PR.
729
+
725
730
  ### Before flipping (operator)
726
731
 
727
732
  1. Confirm the required context name is exactly `Merge gate (task check)` (the aggregator). Do not require primary or failover lane names.
@@ -46,7 +46,17 @@ Probe order (must match engine `probeMonitoringTier` / `resolveDispatchProvider`
46
46
 
47
47
  1. The canonical `templates/agent-prompt-preamble.md` content as the preamble (AGENTS.md read mandate, #810 xBRIEF gate, #798 PowerShell UTF-8, pre-PR + review-cycle mandates).
48
48
  2. The standard worktree prompt (STEP 1-6 from the Prompt Template in `references/core-ops.md`).
49
- 3. The worktree path set to the agent's isolated git worktree.
49
+ 3. ! **Per-worktree story binding (#6233).** Claude Code sub-agents share the parent's hook environment, so a per-worker `DEFT_ACTIVE_SCOPE` pin is not possible. Use this in-session sequence:
50
+ 1. The parent launches the cohort through `deft swarm:launch`, so dispatch PREP registers each worker worktree with its story in the worker-auth assignment record.
51
+ 2. The parent starts the session ritual in each worker worktree (`deft session:start`, then `deft verify:session-ritual -- --tier=gated`).
52
+ 3. The parent holds no `DEFT_ACTIVE_SCOPE` pin. A pin that names a different story than the worktree's assignment is refused.
53
+ 4. The parent gives each sub-agent the absolute path of its worktree, and the sub-agent writes only inside it.
54
+
55
+ The write fence then reads the story for a registered linked worktree from its assignment record. A reader failure, or an assigned story that is missing, ineligible or ambiguous, refuses the write with the failure kind and one repair step. An unregistered linked worktree and the main worktree keep the earlier selection.
56
+
57
+ ! **Fallback:** one headless Claude Code process per story, each with its own `DEFT_ACTIVE_SCOPE`, until the live two-story run in #6242 passes.
58
+
59
+ ! **Guarantee and limits:** this is destination-scoped cooperative fencing. The trusted writer is dispatch PREP (`swarm:launch`). It is not worker isolation: a worker process can still change the record. Coverage is Write/Edit, plus recognized shell destination forms when that policy is set to `enforce`. Other shell writes are not covered.
50
60
  4. ! **`run_in_background: true` (or host equivalent)** for any worker or poller whose loop runs longer than a short task (~3 min) — implementation, fix, and review-cycle workers — so the monitor conversation pane stays interactive (#1880 Gap D). The parent is notified on completion.
51
61
  5. ! **Deliberate model routing (#1739):** resolve `(dispatch_provider=claude, worker_role)` via `task verify:routing` / `task swarm:routing-set` and pass `resolved_model` into the spawn when non-null — stamping the C2 manifest is prep; the recorded model MUST reach the actual spawn call.
52
62
 
@@ -816,7 +816,9 @@ tasks:
816
816
  cmds:
817
817
  - task: engine:invoke
818
818
  vars:
819
- ENGINE_CMD: 'release-publish {{.CLI_ARGS}}'
819
+ # #5805 / #5942: the pin's default project root is its own package dir, so pass the
820
+ # operator root explicitly (an operator --project-root in CLI_ARGS still wins).
821
+ ENGINE_CMD: 'release-publish --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
820
822
 
821
823
  release:rollback:
822
824
  desc: "State-aware release unwind (#716) -- task release:rollback -- <version> [--dry-run] [--allow-low-downloads N] [--allow-data-loss] [--force-strict-0]"
@@ -825,7 +827,9 @@ tasks:
825
827
  cmds:
826
828
  - task: engine:invoke
827
829
  vars:
828
- ENGINE_CMD: 'release-rollback {{.CLI_ARGS}}'
830
+ # #5805 / #5942: the pin's default project root is its own package dir, so pass the
831
+ # operator root explicitly (an operator --project-root in CLI_ARGS still wins).
832
+ ENGINE_CMD: 'release-rollback --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
829
833
 
830
834
  release:e2e:
831
835
  desc: "End-to-end release rehearsal against an auto-created temp repo (#716, #2572 keep+report default) -- task release:e2e [-- --dry-run] [--owner OWNER] [--destroy-repo]"
@@ -834,7 +838,9 @@ tasks:
834
838
  cmds:
835
839
  - task: engine:invoke
836
840
  vars:
837
- ENGINE_CMD: 'release-e2e {{.CLI_ARGS}}'
841
+ # #5805 / #5942: the pin's default project root is its own package dir, so pass the
842
+ # operator root explicitly (an operator --project-root in CLI_ARGS still wins).
843
+ ENGINE_CMD: 'release-e2e --project-root "{{.USER_WORKING_DIR}}" {{.CLI_ARGS}}'
838
844
 
839
845
  release:wait-npm:
840
846
  desc: "Phase 7 wait until both public OVPR packages (@deftai/directive + @deftai/directive-runtime) list the cut version (#4267 / #5490) -- task release:wait-npm -- <version>"
@@ -149,7 +149,8 @@ Common commands:
149
149
  - Bare `evidence` / `disposition` keys are **not** valid (#1620 / Option B #3305). They fail `verify:vbrief-conformance` and are treated as missing by `scope:complete` (no dual-read). Migrate bare keys or narrative-only `Result`/`Verification` workarounds to the namespaced fields above while items are still non-terminal.
150
150
  - Already-terminal items (`completed`/`failed`/`cancelled`/…) are not re-checked for typed evidence; pre-marking items complete to skip the gate is unsupported for the typed path.
151
151
  - `merge`/`review` alone cannot satisfy smoke/UAT/deploy/observed_behavior criteria (title/Acceptance text or explicit axis).
152
- - **Delivery identity (#5710):** with an issue origin, the PR must be associated with the issue as of `merged_at` by one of: (a) a unique sole `deft-story: N` mark in the merge-time PR body (PRs that change only briefs and `CHANGELOG.md` are excluded and never count), (b) a closing keyword (`Closes #N`, `owner/repo#N`, or the issue URL) in the merge-time body, or (c) a Connected issue link at `merged_at`. Brief-in-PR-diff still counts. A mark, keyword or link added after merge does not count, and current `closingIssuesReferences` alone is not enough. Basis (a) scans every merged PR within 20 minutes, `graphql.remaining` ≥ 200 and REST core ≥ 100; any gap refuses. With no issue origin, stamp `plan.metadata.productPullRequest` and complete with `--pr <that number> --merge-commit <sha>`; the repository is the `origin` remote. `--non-delivery` refuses when the stamped PR is merged, and refuses when its merge state cannot be read. `xbrief:preflight` prints one note for a code-bearing brief with no issue origin.
152
+ - **Delivery identity (#5710):** with an issue origin, the PR must be associated with the issue as of `merged_at` by one of: (a) a unique sole `deft-story: N` mark in the merge-time PR body (PRs that change only lifecycle briefs, `CHANGELOG.md` and the spec-drift ledger are excluded and never count), (b) a closing keyword (`Closes #N`, `owner/repo#N`, or the issue URL) in the merge-time body, or (c) a Connected issue link at `merged_at`. Brief-in-PR-diff still counts. A mark, keyword or link added after merge does not count, and current `closingIssuesReferences` alone is not enough. Basis (a) scans every merged PR within 20 minutes, `graphql.remaining` ≥ 200 and REST core ≥ 100; any gap refuses. With no issue origin, stamp `plan.metadata.productPullRequest` and complete with `--pr <that number> --merge-commit <sha>`; the repository is the `origin` remote. `--non-delivery` refuses when the stamped PR is merged, and refuses when its merge state cannot be read. `xbrief:preflight` prints one note for a code-bearing brief with no issue origin.
153
+ - **Lifecycle completion (#680):** completion admission uses the merge-time bases above; there is no separate keyword-only refuse. `swarm:finalize-owed` also lists an active issue-less brief with a stamped `productPullRequest` (shown as `pr #P`, no issue number, no origin-issue check or origin-close); briefs that share a product PR finalize together under one claim. In a batched `swarm:finalize-cohort`, a refused `deft-story` mark is not an error: that story stays pending, unstamped and unswept (`refused_marks`, exit 3 incomplete), and the other stories stamp, sweep, commit and land. A failed changed-file lookup and real delivery errors still fail the batch. `scope:complete` writes the spec-drift ledger as verb output; finalize commits it with the completed briefs, and scope-provenance membership admits exactly `xbrief/.audit/spec-drift-ledger.json` only when the whole change set is a completion move. `verify:changelog-unreleased` needs no new `[Unreleased]` line when the change set versus merge-base (`git diff --name-only --no-renames`) is non-empty and only lifecycle briefs, `CHANGELOG.md` and that ledger, so lifecycle verbs write no CHANGELOG line. Product changes and an empty change set still need one.
153
154
  - `task scope:fail -- xbrief/active/<file>.xbrief.json` -- mark running work failed when the scope cannot complete.
154
155
  - `task scope:cancel -- <path>` -- move a scope to `cancelled/`.
155
156
  - `task scope:restore`, `task scope:block`, `task scope:unblock`, `task scope:demote`, and `task scope:undo:*` -- repair or reverse lifecycle transitions.
@@ -182,6 +183,8 @@ The implementation gate succeeds only for active scope xBRIEFs with `plan.status
182
183
 
183
184
  **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.
184
185
 
186
+ **Small-change lane (#6204):** Under the `rapid` ceremony dial, a scope with stated acceptance commands may use a thin brief: title, issue ref, `file_scope` and acceptance commands only (`emitThinBrief`, `packages/core/src/intake/thin-brief.ts`). The bound defaults to 5 production files and 500 changed lines (added plus deleted, tests included; briefs and CHANGELOG excluded). `plan.policy.ceremonyDial.smallChangeLane` (`maxProductionFiles`, `maxChangedLines`) overrides each field; an invalid value refuses. `scope:promote`, `scope:activate`, `xbrief:preflight`, `verify:ac` and `scope:complete` admit the thin shape, and each one remeasures the cumulative product diff (git, against the lane-admit base in `plan.metadata["x-directive/smallChangeLane"]`; at `scope:complete`, the delivered merge commit against its first parent). A crossed bound, a public-surface change (manifest, entry, task file or export line), an unknown public surface, or a depth other than `rapid` refuses. A crossed bound or public-surface change is recorded on the brief (lane state `crossed`), so every later retry refuses even if the diff shrinks. The public-surface check reads export statements with the TypeScript parser, so a change inside a multi-line export list or exported signature counts. The one remediation is lane exit: convert the scope to the full shape (`escalateThinBriefToFullShape`), which keeps scope identity and acceptance evidence. Raising the dial (#3319) does not clear the refusal. One-PR delivery is not part of this lane; Path B brief-first stays lawful (#6203 / #680).
187
+
185
188
  ```mermaid
186
189
  flowchart TD
187
190
  Candidate["Scope xBRIEF exists"] --> Promote{"In proposed?"}
@@ -722,6 +722,11 @@ Up-to-date-required branch protection plus a required `Merge gate (task check)`
722
722
 
723
723
  ⊗ Mutate GitHub `mergeable_state` to encode semantic/policy readiness — forge enrollment + local probe are the dispositioned alternatives (#4888 Prefer-A Bound Reject E).
724
724
 
725
+ ### Lifecycle PRs: CHANGELOG and spec-drift ledger (#680)
726
+
727
+ - `verify:changelog-unreleased` skips the new-entry compare when the change set versus merge-base (`git diff --name-only --no-renames`) is non-empty and every path is a lifecycle brief (`xbrief|vbrief/<lifecycle>/`), `CHANGELOG.md`, or `xbrief/.audit/spec-drift-ledger.json`. Activation and completion PRs need no operator CHANGELOG line. Product changes and an empty change set keep the requirement.
728
+ - `scope:complete` writes the spec-drift ledger; `swarm:finalize-cohort` commits it with the completed briefs. Membership admits exactly that ledger path only when the whole change set is a completion move. The verbs own these writes, so agents do not hand-write CHANGELOG or ledger lines on a lifecycle PR.
729
+
725
730
  ### Before flipping (operator)
726
731
 
727
732
  1. Confirm the required context name is exactly `Merge gate (task check)` (the aggregator). Do not require primary or failover lane names.
@@ -46,7 +46,17 @@ Probe order (must match engine `probeMonitoringTier` / `resolveDispatchProvider`
46
46
 
47
47
  1. The canonical `templates/agent-prompt-preamble.md` content as the preamble (AGENTS.md read mandate, #810 xBRIEF gate, #798 PowerShell UTF-8, pre-PR + review-cycle mandates).
48
48
  2. The standard worktree prompt (STEP 1-6 from the Prompt Template in `references/core-ops.md`).
49
- 3. The worktree path set to the agent's isolated git worktree.
49
+ 3. ! **Per-worktree story binding (#6233).** Claude Code sub-agents share the parent's hook environment, so a per-worker `DEFT_ACTIVE_SCOPE` pin is not possible. Use this in-session sequence:
50
+ 1. The parent launches the cohort through `deft swarm:launch`, so dispatch PREP registers each worker worktree with its story in the worker-auth assignment record.
51
+ 2. The parent starts the session ritual in each worker worktree (`deft session:start`, then `deft verify:session-ritual -- --tier=gated`).
52
+ 3. The parent holds no `DEFT_ACTIVE_SCOPE` pin. A pin that names a different story than the worktree's assignment is refused.
53
+ 4. The parent gives each sub-agent the absolute path of its worktree, and the sub-agent writes only inside it.
54
+
55
+ The write fence then reads the story for a registered linked worktree from its assignment record. A reader failure, or an assigned story that is missing, ineligible or ambiguous, refuses the write with the failure kind and one repair step. An unregistered linked worktree and the main worktree keep the earlier selection.
56
+
57
+ ! **Fallback:** one headless Claude Code process per story, each with its own `DEFT_ACTIVE_SCOPE`, until the live two-story run in #6242 passes.
58
+
59
+ ! **Guarantee and limits:** this is destination-scoped cooperative fencing. The trusted writer is dispatch PREP (`swarm:launch`). It is not worker isolation: a worker process can still change the record. Coverage is Write/Edit, plus recognized shell destination forms when that policy is set to `enforce`. Other shell writes are not covered.
50
60
  4. ! **`run_in_background: true` (or host equivalent)** for any worker or poller whose loop runs longer than a short task (~3 min) — implementation, fix, and review-cycle workers — so the monitor conversation pane stays interactive (#1880 Gap D). The parent is notified on completion.
51
61
  5. ! **Deliberate model routing (#1739):** resolve `(dispatch_provider=claude, worker_role)` via `task verify:routing` / `task swarm:routing-set` and pass `resolved_model` into the spawn when non-null — stamping the C2 manifest is prep; the recorded model MUST reach the actual spawn call.
52
62