@ikon85/agent-workflow-kit 0.43.0 → 0.44.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 (126) hide show
  1. package/.agents/skills/grill-me/SKILL.md +3 -1
  2. package/.agents/skills/grill-with-docs/SKILL.md +3 -1
  3. package/.agents/skills/kit-update/SKILL.md +9 -11
  4. package/.agents/skills/orchestrate-wave/SKILL.md +8 -8
  5. package/.agents/skills/setup-workflow/SKILL.md +20 -18
  6. package/.agents/skills/setup-workflow/board-sync.md +4 -1
  7. package/.agents/skills/setup-workflow/workflow-advisories.md +3 -2
  8. package/.agents/skills/setup-workflow/worktree-lifecycle.md +36 -31
  9. package/.agents/skills/to-issues/SKILL.md +43 -0
  10. package/.agents/skills/wrapup/SKILL.md +98 -54
  11. package/.claude/skills/grill-me/SKILL.md +3 -1
  12. package/.claude/skills/grill-me-codex/SKILL.md +3 -1
  13. package/.claude/skills/grill-with-docs/SKILL.md +3 -1
  14. package/.claude/skills/grill-with-docs-codex/SKILL.md +3 -1
  15. package/.claude/skills/kit-update/SKILL.md +9 -11
  16. package/.claude/skills/orchestrate-wave/SKILL.md +8 -8
  17. package/.claude/skills/setup-workflow/SKILL.md +20 -18
  18. package/.claude/skills/setup-workflow/board-sync.md +4 -1
  19. package/.claude/skills/setup-workflow/workflow-advisories.md +3 -2
  20. package/.claude/skills/setup-workflow/worktree-lifecycle.md +36 -31
  21. package/.claude/skills/to-issues/SKILL.md +43 -0
  22. package/.claude/skills/wrapup/SKILL.md +98 -54
  23. package/README.md +249 -7
  24. package/agent-workflow-kit.package.json +42 -42
  25. package/package.json +16 -12
  26. package/scripts/marker_lib.py +3 -0
  27. package/scripts/profile_globs.py +26 -45
  28. package/scripts/release-delta-guard.mjs +26 -9
  29. package/scripts/worktree-lifecycle/README.md +57 -160
  30. package/scripts/worktree-lifecycle/capabilities.json +2 -3
  31. package/scripts/worktree-lifecycle/classify.py +480 -0
  32. package/scripts/worktree-lifecycle/cleanup.py +9 -29
  33. package/scripts/worktree-lifecycle/core.py +68 -1429
  34. package/scripts/worktree-lifecycle/ignore_seed.py +1 -1
  35. package/scripts/worktree-lifecycle/profile.py +46 -29
  36. package/scripts/worktree-lifecycle/setup.py +7 -19
  37. package/scripts/wrapup-land.py +1292 -545
  38. package/src/consumer-migrations.json +1 -16
  39. package/src/lib/bundle.mjs +31 -1
  40. package/docs/adr/0001-consumer-divergence-policy.md +0 -53
  41. package/docs/adr/0002-capability-gated-orchestration.md +0 -70
  42. package/docs/adr/0003-kit-core-and-project-extension-lifecycle.md +0 -63
  43. package/docs/adr/0004-release-intent-is-a-version-tag.md +0 -64
  44. package/docs/adr/0005-to-issues-is-the-planning-facade.md +0 -42
  45. package/docs/adr/0006-routing-knowledge-access-and-policy-are-separate.md +0 -95
  46. package/docs/adr/0007-session-teardown-requires-provenance-bound-ownership.md +0 -88
  47. package/docs/adr/0008-planning-ignore-rules-are-offered-never-installed.md +0 -84
  48. package/docs/adr/0009-teardown-authority-is-stateless-repository-classification.md +0 -101
  49. package/docs/adr/0010-model-roster-replaces-the-optimization-dial.md +0 -87
  50. package/docs/agents/board-sync.md +0 -74
  51. package/docs/agents/code-review.md +0 -14
  52. package/docs/agents/workflow-capabilities.json +0 -28
  53. package/docs/research/agent-task-taxonomy-benchmark-coverage.md +0 -451
  54. package/docs/research/benchlm-routing-source.md +0 -198
  55. package/docs/research/consumer-owned-protocol-files.md +0 -238
  56. package/docs/research/frontend-agent-benchmarks.md +0 -282
  57. package/docs/research/model-effort-routing-benchmarks.md +0 -261
  58. package/docs/research/provider-neutral-agent-routing.md +0 -207
  59. package/docs/research/wave-152-consumer-acceptance.md +0 -98
  60. package/docs/research/wave-43-script-hook-census.md +0 -128
  61. package/scripts/build-kit.mjs +0 -117
  62. package/scripts/build-kit.test.mjs +0 -207
  63. package/scripts/census/census.test.mjs +0 -252
  64. package/scripts/census/state.test.mjs +0 -15
  65. package/scripts/census/transaction.test.mjs +0 -103
  66. package/scripts/census-contract.test.mjs +0 -227
  67. package/scripts/check-kit-staleness.mjs +0 -45
  68. package/scripts/check-kit-staleness.test.mjs +0 -19
  69. package/scripts/codex-exec-scenarios/fake-codex.mjs +0 -165
  70. package/scripts/codex-exec.test.mjs +0 -871
  71. package/scripts/grill-census-wiring-guard.mjs +0 -87
  72. package/scripts/grill-census-wiring-guard.test.mjs +0 -107
  73. package/scripts/kit-release.test.mjs +0 -273
  74. package/scripts/kit-update-pr.test.mjs +0 -151
  75. package/scripts/lib/audit-refs.mjs +0 -146
  76. package/scripts/lib/scrub.mjs +0 -113
  77. package/scripts/lib/scrub.test.mjs +0 -187
  78. package/scripts/memory-lifecycle/memory-lifecycle.test.mjs +0 -170
  79. package/scripts/portability_profile_scan.py +0 -53
  80. package/scripts/release-delta-guard.test.mjs +0 -174
  81. package/scripts/release-parity.test.mjs +0 -90
  82. package/scripts/release-state.test.mjs +0 -360
  83. package/scripts/test_anchor_table.py +0 -69
  84. package/scripts/test_board_bootstrap.py +0 -348
  85. package/scripts/test_board_sync.py +0 -208
  86. package/scripts/test_board_sync_create_idempotency.py +0 -117
  87. package/scripts/test_board_sync_wave_title.py +0 -120
  88. package/scripts/test_census_backstop.py +0 -712
  89. package/scripts/test_census_forward_contract.py +0 -91
  90. package/scripts/test_census_update_contract.test.mjs +0 -454
  91. package/scripts/test_codex_adapter_sync_contract.py +0 -169
  92. package/scripts/test_dist_kit_smoke.py +0 -220
  93. package/scripts/test_drift_guard_diagnostics.py +0 -295
  94. package/scripts/test_issue_claim_contract.py +0 -169
  95. package/scripts/test_kit_docs_language_census.py +0 -178
  96. package/scripts/test_marker_lib.py +0 -162
  97. package/scripts/test_orchestrate_wave_contract.py +0 -381
  98. package/scripts/test_pr_body_check.py +0 -264
  99. package/scripts/test_profile_globs.py +0 -280
  100. package/scripts/test_program_planning_contract.py +0 -133
  101. package/scripts/test_release_authorization_contract.py +0 -101
  102. package/scripts/test_render_anchor.py +0 -267
  103. package/scripts/test_retro_wrapup_contract.py +0 -153
  104. package/scripts/test_skill_code_review_seed.py +0 -89
  105. package/scripts/test_skill_codex_exec_lifecycle.py +0 -123
  106. package/scripts/test_skill_frontmatter_lint.py +0 -234
  107. package/scripts/test_skill_gh_lint.py +0 -124
  108. package/scripts/test_skill_language_census.py +0 -254
  109. package/scripts/test_skill_optional_readiness.py +0 -171
  110. package/scripts/test_skill_portability_lint.py +0 -866
  111. package/scripts/test_skill_precommit_template.py +0 -30
  112. package/scripts/test_skill_publish_audit.py +0 -358
  113. package/scripts/test_skill_readiness_contract.py +0 -264
  114. package/scripts/test_skill_readiness_preflight.py +0 -180
  115. package/scripts/test_skill_required_readiness.py +0 -233
  116. package/scripts/test_skill_selfcontainment_lint.py +0 -255
  117. package/scripts/test_skill_setup_workflow_seeds.py +0 -691
  118. package/scripts/test_skill_stale_name_lint.py +0 -126
  119. package/scripts/test_skill_surface_refs.py +0 -300
  120. package/scripts/test_skill_trailing_artifact_lint.py +0 -71
  121. package/scripts/test_tdd_contract.py +0 -78
  122. package/scripts/test_worktree_ignore_seed.py +0 -320
  123. package/scripts/test_worktree_setup_base_guard.py +0 -140
  124. package/scripts/test_worktree_wrapup_contract.py +0 -1737
  125. package/scripts/test_wrapup_land.py +0 -428
  126. package/scripts/worktree-lifecycle/session.py +0 -1857
@@ -52,7 +52,9 @@ For a cross-cutting plan, run `python3 .claude/hooks/drift-guard.py --census-sta
52
52
 
53
53
  ## Plan-lock — writing PLAN.md
54
54
 
55
- Once all decisions are made (plan locked, before sign-off/handoff) and the session runs in a **worktree** write the locked plan as `PLAN.md` to the worktree root. `PLAN.md` is **expected** to be ignored by git so it never travels over git — the kit never edits your `.gitignore` by itself, but `/setup-workflow` offers to add that rule (consistent with CLAUDE.md "plan inside the worktree"). This way the locked plan survives a session cut and `to-prd` finds its default source. Continuing same-session work **without** a worktree stays allowed (conversation = source); but for a deliberate **session cut** before `to-prd`, `PLAN.md` is mandatory. (The `-codex` variant already writes `PLAN.md` anyway.)
55
+ Once all decisions are made (plan locked, before sign-off/handoff) write the locked plan as `PLAN.md` **where the session already runs**. Planning creates no worktree: a worktree isolates a build, so it belongs to the implementing session, which creates it when the build starts. `PLAN.md` is **expected** to be ignored by git so it never travels over git — the kit never edits your `.gitignore` by itself, but `/setup-workflow` offers to add that rule. Being ignored is also what makes it scratch: the repository has declared it not-work, so it is deletable at teardown and needs no cleanup step of its own. This way the locked plan survives a session cut and `to-prd` finds its default source. Continuing same-session work stays allowed (conversation = source); but for a deliberate **session cut** before `to-prd`, `PLAN.md` is mandatory. (The `-codex` variant already writes `PLAN.md` anyway.)
56
+
57
+ **Durable output is the opposite case.** Domain-model or glossary edits, decision records and research notes this grill produced are **not** scratch — they are ordinary work and have to reach a commit. Land them with `$wrapup`: a planning session with no worktree takes its Content route, which claims an explicitly confirmed file list and opens the ordinary PR, with no teardown half. Never leave them behind as an uncommitted session leftover.
56
58
 
57
59
  ## Re-grill reconcile — execute-ready (Wave 26)
58
60
 
@@ -40,7 +40,9 @@ For a cross-cutting plan, run `python3 .claude/hooks/drift-guard.py --census-sta
40
40
 
41
41
  ## Plan-lock — writing PLAN.md
42
42
 
43
- Once all decisions are made (plan locked, before sign-off/handoff) and the session runs in a **worktree** write the locked plan as `PLAN.md` to the worktree root. `PLAN.md` is **expected** to be ignored by git so it never travels over git — the kit never edits your `.gitignore` by itself, but `/setup-workflow` offers to add that rule (consistent with CLAUDE.md "plan inside the worktree"). This way the locked plan survives a session cut and `to-prd` finds its default source. Continuing same-session work **without** a worktree stays allowed (conversation = source); but for a deliberate **session cut** before `to-prd`, `PLAN.md` is mandatory. (The `-codex` variant already writes `PLAN.md` anyway.)
43
+ Once all decisions are made (plan locked, before sign-off/handoff) write the locked plan as `PLAN.md` **where the session already runs**. Planning creates no worktree: a worktree isolates a build, so it belongs to the implementing session, which creates it when the build starts. `PLAN.md` is **expected** to be ignored by git so it never travels over git — the kit never edits your `.gitignore` by itself, but `/setup-workflow` offers to add that rule. Being ignored is also what makes it scratch: the repository has declared it not-work, so it is deletable at teardown and needs no cleanup step of its own. This way the locked plan survives a session cut and `to-prd` finds its default source. Continuing same-session work stays allowed (conversation = source); but for a deliberate **session cut** before `to-prd`, `PLAN.md` is mandatory. (The `-codex` variant already writes `PLAN.md` anyway.)
44
+
45
+ **Durable output is the opposite case.** This grill writes `CONTEXT.md` and ADR updates inline, by design, and a session often adds research notes as well. None of that is scratch — it is ordinary work and has to reach a commit. Land it with `$wrapup`: a planning session with no worktree takes its Content route, which claims an explicitly confirmed file list and opens the ordinary PR, with no teardown half. Never leave the documentation this grill just sharpened behind as an uncommitted session leftover.
44
46
 
45
47
  </plan-lock>
46
48
 
@@ -113,10 +113,10 @@ release contain the same artifact.
113
113
  pull request all name the same outstanding actions. Each action names the
114
114
  workflow that resolves it, the Consumer file that carries the decision, and
115
115
  the exact missing decision. `kit-update` only detects and reports it: it
116
- never writes the decision, never infers a value, and never invents or
117
- auto-accepts a pattern that would grant deletion authority. An empty but
118
- explicit decision is a committed decision and clears the action; a missing
119
- one keeps it pending on every rerun.
116
+ never writes the decision and never infers a value. An empty but explicit
117
+ decision is a committed decision and clears the action; a missing one keeps
118
+ it pending on every rerun. A registry with no entries is the normal state
119
+ report no outstanding action rather than inventing one.
120
120
 
121
121
  For each conflicted kit-shipped file, always ask the user whether the local
122
122
  edit is a generic improvement or project-specific; never decide or act
@@ -150,16 +150,14 @@ release contain the same artifact.
150
150
  python3 scripts/profile_globs.py docs/agents/workflow-capabilities.json
151
151
  ```
152
152
 
153
- Every consumer-profile glob — Worktree Lifecycle `scratchPatterns` and
154
- `wrapup.landingGeneratedArtifactPatterns`, Workflow Advisories
153
+ Every consumer-profile glob — the Workflow Advisories keys
155
154
  `baseline.sourceGlobs` and the `preRefactor`/`stopChecks` surface globs — is
156
155
  matched by one shared repository-relative dialect. A pattern written for an
157
156
  older matcher can narrow or widen. The check names each such pattern with
158
- the witness path that proves the difference and marks the keys that carry
159
- deletion authority; exit code 1 means at least one needs review. Report the
160
- named patterns and let the user rewrite them. The updater never rewrites a
161
- consumer pattern, and a widened deletion-authority pattern is never accepted
162
- silently — an update must not expand what cleanup may remove. A missing or
157
+ the witness path that proves the difference; exit code 1 means at least one
158
+ needs review. Report the named patterns and let the user rewrite them. The
159
+ updater never rewrites a consumer pattern. No Worktree Lifecycle decision
160
+ reads a glob, so an update cannot expand what cleanup removes. A missing or
163
161
  disabled profile leaves nothing to review and does not invalidate the
164
162
  update.
165
163
 
@@ -126,7 +126,7 @@ replace the ~30-second heartbeat; otherwise the standing heartbeat remains requi
126
126
 
127
127
  1. **Read everything**: the anchor body, every sub-issue body (each has a Handoff
128
128
  block: scope, blast-radius, live-verify, PR line), and the locked plan /
129
- plan-review doc in the planning worktree (file-exact).
129
+ plan-review doc the handoff points at, file-exact when one is on disk.
130
130
  2. **Select exact commands or the generic fallback.** If the readiness result
131
131
  activated `projectRecipe`, use the loaded filled recipe wherever a phase below
132
132
  points at a `§`-section. Otherwise use each phase's generic fallback; the
@@ -141,9 +141,10 @@ replace the ~30-second heartbeat; otherwise the standing heartbeat remains requi
141
141
  LOCAL annotated tag, so two sessions racing one wave cannot both win. Either
142
142
  `acquired: false` or a work signal you did not create means another session
143
143
  owns the wave — **STOP**, report the returned `claim.owner` plus the exact
144
- branch/worktree, touch nothing. After acquisition, begin the claim-bound teardown receipt with `python3 scripts/worktree-lifecycle/session.py begin --anchor <anchor> --owner <claim-owner> --base <wave-HEAD>`; claim and receipt stay local — never push them.
145
- 4. **Wave worktree**: reuse the planning worktree (never re-create; the handoff
146
- points there). Bring its branch to current `main`:
144
+ branch/worktree, touch nothing. The claim stays local — never push it.
145
+ 4. **Wave worktree**: reuse the planning worktree when the handoff names one,
146
+ never re-creating it; planning binds to no worktree, so a wave may need one
147
+ cut with your worktree helper. Bring its branch to current `main`:
147
148
  `git -C <wave> merge --ff-only origin/main` (if your repo guards destructive
148
149
  git, ff-merge is the safe path — not `reset --hard`). Install dependencies with
149
150
  your package manager after (the lockfile may have moved). A plan doc the repository
@@ -195,8 +196,7 @@ disjoint wave, conflict hub first. Dispatch only `FREI` slices: re-read
195
196
  `frontier <anchor#>` before each wave and clear changed edges only via `dep-remove`.
196
197
  Before each slice, bind **(a) inline vs delegate** and **(b) tier + effort** under
197
198
  Standing rules. Tiny mechanical work may stay inline.
198
- For Path A/B, create each new worktree through the active receipt: `python3 scripts/worktree-lifecycle/session.py create --anchor <anchor> --owner <claim-owner> --base <wave-HEAD> --profile <profile> <slice-issue> <slug> <type>`.
199
- It refuses reused/pre-existing targets; never replace this ownership proof with raw `git worktree add`.
199
+ For Path A/B, create each new worktree with your project's worktree helper — in this kit `python3 scripts/worktree-lifecycle/setup.py --profile <profile> --base <wave-HEAD> <slice-issue> <slug> <type>`, which rolls the worktree and branch back if project setup fails.
200
200
  - **Claim each slice issue at builder launch — the wave claim is not a slice
201
201
  claim.** It guards the anchor on this machine only; the slice issue is the
202
202
  grabbable unit a second machine or cloud agent sees. Before dispatch, skip and
@@ -358,8 +358,8 @@ written · merge order documented.
358
358
  - A skill edited during the wave → sync its dual-surface mirror in the SAME PR
359
359
  using the tool named by `§Landing` when present; mirror parity remains a pre-PR
360
360
  gate.
361
- - After reading every `ANNAHMEN.md`, seal the receipt, inspect it against fetched canonical `main`, then run its `teardown`; only ancestry/one-to-one patch-equivalent exact owned OIDs are compare-deleted, while foreign targets, unique/ambiguous content, changed OIDs, dirty/protected worktrees, and open/unknown PR evidence stop.
362
- - Keep the completed receipt as recovery-OID evidence; only then release this run's wave claim.
361
+ - After reading every `ANNAHMEN.md`, tear each landed slice worktree down from the repository's current state: tracked changes, non-ignored untracked files, an unmerged branch, or a protected branch stop that one worktree and name the cause.
362
+ - Only once every worktree decision is made, release this run's wave claim.
363
363
 
364
364
  **Done when:** no orphan process · this run's wave claim removed · this run's
365
365
  unlanded slice claims released · ANNAHMEN propagated ·
@@ -204,27 +204,28 @@ Worktree Lifecycle for this repository?"* Offer exactly **Yes**, **Later**, and
204
204
 
205
205
  - **Yes** — create or deepen only the `worktreeLifecycle` section in
206
206
  `docs/agents/workflow-capabilities.json`, preserve every other section and
207
- unknown key, reconcile an explicit consumer-derived `scratchPatterns` array,
208
- explicitly derive and review the consumer's
209
- `wrapup.landingGeneratedArtifactPatterns` array from real landing outputs,
210
- and reconcile only the exact kit-owned hook commands listed in the seed.
207
+ unknown key, reconcile both branch templates `branchTemplate` for an
208
+ issue-anchored slice and `contentBranchTemplate` (default `{type}/{slug}`)
209
+ for the issue-less branch of a durable-content session — and reconcile only
210
+ the exact kit-owned hook commands listed in the seed.
211
211
  - **Later / No** — record the choice in the tracked profile without installing
212
212
  hook wiring. Ordinary reruns do not ask again.
213
213
  - **Existing** — adopt the current section and wiring without normalizing
214
- consumer-owned values. Preserve an existing landing-artifact policy
215
- byte-for-byte; if it is missing, surface the explicit derivation decision and
216
- do not write a default.
214
+ consumer-owned values, including keys this kit no longer reads.
217
215
  - **Disable** — remove only the exact kit-owned hook commands first, then set
218
216
  `enabled: false`; retain the profile, setup policy, and unknown keys.
219
217
 
220
- Whenever a profile already carries patterns on **Yes** over an existing
221
- section and on **Existing** run
218
+ Reconcile no deletion-pattern list at any state. Deletion policy has exactly
219
+ one configuration surface, the ignore mechanism, so a profile that still
220
+ carries a pattern key from an older kit keeps it verbatim as consumer data: it
221
+ is ignored in silence, never rewritten and never reported.
222
+
223
+ Whenever a profile already carries Workflow Advisories globs — on **Yes** over
224
+ an existing section and on **Existing** — run
222
225
  `python3 scripts/profile_globs.py docs/agents/workflow-capabilities.json` and
223
226
  report every pattern it names. Patterns whose match set narrows or widens under
224
- the shared dialect are a consumer decision: name them with their witness path,
225
- mark the deletion-authority keys, and let the consumer rewrite them. Never
226
- rewrite a pattern for them, and never accept a widened deletion-authority
227
- pattern silently.
227
+ the shared dialect are a consumer decision: name them with their witness path
228
+ and let the consumer rewrite them. Never rewrite a pattern for them.
228
229
 
229
230
  The default setup entry is
230
231
  `python3 scripts/worktree-lifecycle/setup.py`; a proven consumer-native helper
@@ -452,8 +453,9 @@ step may write `.gitignore`; `init` and `update` reconciliation never reach the
452
453
  seeder.
453
454
 
454
455
  Report `appended · nothing to do (already ignored) · declined · blocked
455
- (consumer-edited block)`. After an approval — and only then — the Section A4
456
- `scratchPatterns` derivation has real ignored planning artefacts to read.
456
+ (consumer-edited block)`. After an approval — and only then — those artefacts
457
+ are Scratch, because being ignored is the whole of what makes a file deletable
458
+ at teardown.
457
459
 
458
460
  ### 3. Section B — Triage labels
459
461
 
@@ -605,9 +607,9 @@ unknown consumer keys share this profile. Apply the transition and hook
605
607
  ownership rules from [worktree-lifecycle.md](./worktree-lifecycle.md),
606
608
  [workflow-advisories.md](./workflow-advisories.md), and
607
609
  [safety-guardrails.md](./safety-guardrails.md) transactionally.
608
- The landing-artifact policy is deletion authority: it is always an explicit
609
- consumer-reviewed setup value, never an update-time default or an inference
610
- from ignored paths.
610
+ The profile carries structural facts only; it holds no deletion policy, because
611
+ the ignore mechanism is the single surface that decides what teardown may
612
+ remove.
611
613
 
612
614
  For Memory Lifecycle, use only the deterministic setup helper from Section A5.
613
615
  Do not copy templates with shell commands or edit the capability profile by
@@ -24,6 +24,8 @@ How the board-managed workflow skills (`to-prd`, `to-issues`, `board-to-waves`,
24
24
 
25
25
  The optional `wrapup` block is a wrapup-only switch, not a board field: `wrapup.remoteBranchSweep` (default `false`) gates `wrapup` Step 5d's remote-branch sweep — `false`/missing (the shipped default) means Step 5d only reports the count of stale merged-PR remotes it found; `true` lets it actually `git push origin --delete` them. Flip it to `true` once you trust the sweep in your repo.
26
26
 
27
+ `wrapup.censusTrackingIssue` (default `false`) is the second switch in that block. It gates `wrapup` Step 5f's tracking issue: `false`/missing (the shipped default) means a stale census verdict is reported as a session-end finding only; `true` additionally opens — or, on a later session, updates — one marker-identified tracking issue so the finding survives the session. The finding itself never blocks a landing either way, and the recovery route stays a dedicated pull request, never a census file mirrored between checkouts.
28
+
27
29
  <!-- board-sync:profile -->
28
30
  ```json
29
31
  {
@@ -75,7 +77,8 @@ The optional `wrapup` block is a wrapup-only switch, not a board field: `wrapup.
75
77
  "wavePrefix": "Wave"
76
78
  },
77
79
  "wrapup": {
78
- "remoteBranchSweep": false
80
+ "remoteBranchSweep": false,
81
+ "censusTrackingIssue": false
79
82
  }
80
83
  }
81
84
  ```
@@ -78,8 +78,9 @@ project commands from the tools already present, then asks before activating.
78
78
 
79
79
  `baseline.sourceGlobs`, `preRefactor.surfaces[].globs`, and
80
80
  `stopChecks.surfaces[].globs` are matched by the one shared dialect in
81
- `scripts/profile_globs.py` the same matcher Worktree Lifecycle uses for its
82
- scratch and landing-artifact policies. There is no second matcher and no
81
+ `scripts/profile_globs.py`. They are the only consumer-profile globs the kit
82
+ reads: Worktree Lifecycle carries no pattern list, because the ignore mechanism
83
+ is the single deletion-policy surface. There is no second matcher and no
83
84
  per-capability variant:
84
85
 
85
86
  - `*` matches any run of characters inside one path segment, never `/`.
@@ -29,7 +29,6 @@ advisory, and safe cleanup policy as one unit.
29
29
  "operations": [
30
30
  "record-choice",
31
31
  "reconcile-profile-enabled",
32
- "reconcile-landing-artifact-policy",
33
32
  "reconcile-hook-wiring"
34
33
  ]
35
34
  },
@@ -51,8 +50,7 @@ advisory, and safe cleanup policy as one unit.
51
50
  "state": "existing",
52
51
  "choice": "yes",
53
52
  "operations": [
54
- "adopt-existing",
55
- "reconcile-landing-artifact-policy"
53
+ "adopt-existing"
56
54
  ]
57
55
  },
58
56
  {
@@ -105,28 +103,34 @@ approved step may write `.gitignore`.
105
103
 
106
104
  ## Scratch classification and sweep
107
105
 
108
- Reconcile an explicit `scratchPatterns` array when enabling a new profile.
109
- Derive its glob values from the consumer's ignored planning artefacts; an empty
110
- array is valid. Existing values are consumer-owned and remain byte-identical on
111
- adoption or rerun. Core never supplies filename defaults the offered ignore
112
- rules above are what give that derivation something real to read.
113
-
114
- Also reconcile an explicit
115
- `wrapup.landingGeneratedArtifactPatterns` array. Derive candidates from the
116
- consumer's real landing commands and ignored outputs, show the exact list for
117
- review, and write it only as part of that explicit setup decision. Never copy
118
- another repository's values or infer deletion authority from `.gitignore`
119
- alone. An empty array is valid. Existing configured values remain byte-identical.
120
- If an existing enabled profile lacks the key, report one actionable setup
121
- decision and leave the project layer unchanged until the consumer confirms the
122
- derived list.
106
+ Reconcile **no** pattern list. Deletion policy has exactly one configuration
107
+ surface, the ignore mechanism: a file is Scratch deletable at teardown —
108
+ precisely when the repository's own exclude sources classify it as ignored.
109
+ Making a file deletable therefore means ignoring it, which is what the offered
110
+ planning-artifact rules above do. Setup never derives, writes, or reviews a
111
+ deletion pattern, and a profile that still carries one from an older kit keeps
112
+ it as consumer data: the loader ignores unknown keys in silence, so there is
113
+ nothing to migrate and nothing to warn about.
114
+
115
+ ## Branch templates
116
+
117
+ `branchTemplate` names the branch of an issue-anchored slice and renders
118
+ `{type}`, `{issue}`, and `{slug}`. `contentBranchTemplate` names the issue-less
119
+ branch a session cuts when its output is durable content a planning session
120
+ has no issue number — and renders `{type}` and `{slug}` only; an `{issue}`
121
+ placeholder in it is refused rather than filled with a guess.
122
+
123
+ Reconcile `contentBranchTemplate` with the default `{type}/{slug}` when
124
+ enabling a new profile, and offer the consumer their own naming instead.
125
+ An existing value is consumer-owned and remains byte-identical on adoption or
126
+ rerun.
123
127
 
124
128
  ## Profile glob dialect
125
129
 
126
- Every consumer-profile glob in this kit — Worktree Lifecycle and Workflow
127
- Advisories alike is matched by the one shared dialect in
128
- `scripts/profile_globs.py`. There is no second matcher and no per-capability
129
- variant:
130
+ Every consumer-profile glob in this kit — the Workflow Advisories keys
131
+ `baseline.sourceGlobs`, the `preRefactor`/`stopChecks` surface globs is
132
+ matched by the one shared dialect in `scripts/profile_globs.py`. There is no
133
+ second matcher and no per-capability variant:
130
134
 
131
135
  - `*` matches any run of characters inside one path segment, never `/`.
132
136
  - `?` matches exactly one character inside one path segment.
@@ -147,14 +151,15 @@ trusting its patterns:
147
151
  python3 scripts/profile_globs.py docs/agents/workflow-capabilities.json
148
152
  ```
149
153
 
150
- The check names every pattern whose match set narrows or widens against that
151
- key's legacy matcher, prints the concrete witness path that proves the
152
- difference, and marks the keys that carry deletion authority. Exit code 1 means
153
- at least one pattern needs review. Report the named patterns and let the
154
- consumer rewrite them; never migrate a pattern automatically and never treat a
155
- widened deletion-authority pattern as an accepted default. The check reads the
156
- profile and never edits it.
154
+ The check names every pattern whose match set narrows or widens against the
155
+ legacy matcher and prints the concrete witness path that proves the difference.
156
+ Exit code 1 means at least one pattern needs review. Report the named patterns
157
+ and let the consumer rewrite them; never migrate a pattern automatically. The
158
+ check reads the profile and never edits it. No Worktree Lifecycle decision
159
+ reads a glob, so a pattern here can widen only what an advisory selects, never
160
+ what teardown removes.
157
161
 
158
162
  The shipped read-only inventory is
159
- `python3 scripts/worktree-lifecycle/cleanup.py sweep`. The same profile powers
160
- its branch issue extraction and scratch-only cleanup verdicts.
163
+ `python3 scripts/worktree-lifecycle/cleanup.py sweep`. The profile powers its
164
+ branch issue extraction; the scratch each row reports comes from the same
165
+ stateless classification teardown itself uses, never from a profile pattern.
@@ -505,3 +505,46 @@ The Program graph engine emits `planning-mode=program` in its own counted audit
505
505
  after the complete preview gate; the facade relays that audit unchanged.
506
506
 
507
507
  Do NOT close or modify any parent issue beyond the promote stamp.
508
+
509
+ ### 8. End state — name what the session leaves behind
510
+
511
+ Publication is not the end of the session. `to-issues` **never deletes** what it
512
+ leaves behind — the locked plan is the implementing session's input and the
513
+ assumption log is `$wrapup`'s. Classify, report, hand over.
514
+
515
+ Read the classes from the repository itself, never from a pattern list — git's
516
+ own taxonomy is the classification:
517
+
518
+ ```bash
519
+ git status --short # tracked edits + untracked, non-ignored files
520
+ git status --short --ignored # the same, plus the ignored paths, marked `!!`
521
+ ```
522
+
523
+ - **Durable content** — everything the first command already lists. Domain-model
524
+ or glossary updates, decision records, research notes, any tracked edit the
525
+ planning produced. This is ordinary work: it has to reach a commit and the
526
+ ordinary PR gate. `to-issues` does not commit it.
527
+ - **Scratch** — the `!!` entries only the second command adds: the locked plan,
528
+ its review log, the assumption log. The repository has already declared them
529
+ not-work, so they are deletable at teardown and die with the checkout they
530
+ were written in. Leave them here — the implementing session reads the plan and
531
+ `$wrapup` reads the assumption log.
532
+ - **Nothing** — neither class present. Report it. An empty end state is a
533
+ result, not silence.
534
+
535
+ Then emit the state report — exactly two lines, on every run:
536
+
537
+ ```
538
+ end state: durable=<n file(s) | none> · scratch=<n file(s) | none>
539
+ next: <$wrapup — lands the durable content | nothing to land — this session is done>
540
+ ```
541
+
542
+ `$wrapup` is **user-invoked only**: name it as the next step, never call it from
543
+ here.
544
+
545
+ **A project with no worktree helper changes nothing about this.** The
546
+ classification is git's, not the worktree layout's, and `$wrapup` lands durable
547
+ content from whichever checkout it runs in — its Content route exists precisely
548
+ for a session that has no worktree and no slice. Report the situation as
549
+ observed instead of assuming a worktree convention the project may not have, and
550
+ never propose creating one just to have something to land through.
@@ -9,10 +9,13 @@ description: >-
9
9
  merged-branch leftovers (local + stale remote whose PR is merged). If the
10
10
  slice isn't landed yet, it first makes it landable (Step 0): commits a dirty
11
11
  tree (after an .env/secret check), pushes, and opens the PR — reusing one if
12
- it already exists. User-triggered only (never auto-invoke, never hook). Aborts
13
- hard only on: not in a feature worktree, a detected .env/secret, a rejected
14
- push, a conflicting PR, terminal red checks, or checks still pending after
15
- the bounded wait budget.
12
+ it already exists. Second route (no worktree, no slice): durable content dirty
13
+ in the main checkout lands via one confirmed, hash-verified file claim on an
14
+ issue-less branch bystanders untouched, no teardown. User-triggered
15
+ only (never auto-invoke, never hook). Aborts hard only on: the worktree flow
16
+ on the main checkout or a protected branch, a detached or unborn HEAD, a
17
+ detected .env/secret, a rejected push, a conflicting PR, terminal red checks,
18
+ or checks still pending after the bounded wait budget.
16
19
  ---
17
20
 
18
21
  <!-- project-extension:protocol-v1:start -->
@@ -48,7 +51,7 @@ Run **in the worktree**:
48
51
  ```bash
49
52
  python3 scripts/wrapup-land.py preflight
50
53
  ```
51
- Hard stop (the only pure precondition): not in a feature worktree / on `main` — the script exits 1. The report carries everything the later steps need: dirty files, `.env` hits, secret-grep hits, issue + parent (leaf vs. anchor slice), existing PR + whether its body has a `**Retro:**` line, parsed `ANNAHMEN.md` drift lines, profile values (`retro_values`, `vor_bau`, remote-sweep switch).
54
+ Hard stop (the only pure preconditions): the main checkout, a protected branch, a detached HEAD, or an unborn branch — the script exits 1 and names which. Any other born, attached worktree qualifies, whatever its name or location. The report carries everything the later steps need: dirty files, `.env` hits, secret-grep hits, issue + parent (leaf vs. anchor slice), existing PR + whether its body has a `**Retro:**` line, parsed `ANNAHMEN.md` drift lines, profile values (`retro_values`, `vor_bau`, remote-sweep switch).
52
55
 
53
56
  Then run:
54
57
 
@@ -101,68 +104,109 @@ Run **from the main tree** (the script refuses inside the worktree — an in-wor
101
104
  ```bash
102
105
  python3 scripts/wrapup-land.py land --branch "<branch>" --title "<title>" --body-file /tmp/wrapup-pr-body.md
103
106
  ```
104
- One call covers: push → PR create/reuse (+ drift markers merged into the body) → `pr-body-check.py` gate (exit 1 = STOP, exit 2 = fail-open warning) → merge gate (pending/null-conclusion checks poll for up to 20 minutes with progress on stderr; terminal red / `CONFLICTING` / timeout = STOP; known zero-step billing or runner failures are named `infrastructure failure`; an already-`MERGED` PR resumes at teardown) → **merge** (`--merge` + `--delete-branch`, verified `MERGED`) → dev-server kill (`.dev-ports` ports + cwd-under-worktree walk, own shell ancestry excluded) → worktree remove (no `--force`; refusal = STOP, check surviving processes first) → main `--ff-only` pull + `branch -d` → issue-close verify (auto-close misses are closed manually) → local merged-branch sweep (`-d` only — squash/rebase-merged branches stay a manual call by design) → remote merged-PR sweep (opt-in `wrapup.remoteBranchSweep` in the board profile; PR-status-authoritative via `ls-remote`; deleted remote branches are restorable from the PR page) → anchor-sync (dry-run diff in the report) + anchor completeness check + `execute-ready-check --mode audit` → **upward propagation:** if the anchor's native parent is a Program-PRD, `program-sync` refreshes its Wellenplan (Status + Issue cells) and checks off mechanically completed Phasen-Gates — the slice event is visible at the program level, not only in the wave (`program_sync` block in the report; skipped when the parent isn't a program).
107
+ One call covers: push → PR create/reuse (+ drift markers merged into the body) → `pr-body-check.py` gate (exit 1 = STOP, exit 2 = fail-open warning) → merge gate (pending/null-conclusion checks poll for up to 20 minutes with progress on stderr; terminal red / `CONFLICTING` / timeout = STOP; known zero-step billing or runner failures are named `infrastructure failure`; an already-`MERGED` PR resumes at teardown) → **merge** (`--merge` + `--delete-branch`, verified `MERGED`) → dev-server kill (`.dev-ports` listeners only, own shell ancestry excluded) → teardown classification + scratch removal → worktree remove (no `--force`; refusal = STOP, check surviving processes first) → integration-branch `--ff-only` pull + branch retirement by authority → issue-close verify (auto-close misses are closed manually) → local merged-branch sweep (`-d` only — squash/rebase-merged branches stay a manual call by design) → remote merged-PR sweep (opt-in `wrapup.remoteBranchSweep` in the board profile; PR-status-authoritative via `ls-remote`; deleted remote branches are restorable from the PR page) → anchor-sync (dry-run diff in the report) + anchor completeness check + `execute-ready-check --mode audit` → **upward propagation:** if the anchor's native parent is a Program-PRD, `program-sync` refreshes its Wellenplan (Status + Issue cells) and checks off mechanically completed Phasen-Gates — the slice event is visible at the program level, not only in the wave (`program_sync` block in the report; skipped when the parent isn't a program) → **census freshness** (Step 5f, see below).
108
+
109
+ STOP → diagnose in the main conversation, fix, re-run `land`. Re-running is the
110
+ only recovery route there is: every step re-reads present state (is the remote
111
+ already at this commit? does the PR exist? is it merged? is the worktree still
112
+ there?) and skips what is already done, so an interrupted landing resumes
113
+ exactly where it stopped. The report's `skipped` list names what it found done.
114
+
115
+ Teardown always runs, and running `/wrapup` in a worktree *is* its
116
+ authorization — including a worktree an external tool created under a foreign
117
+ name and path, and a branch that carries no issue number. Teardown authority is
118
+ the repository's current state, nothing else: a tracked change or an unmerged
119
+ path blocks, an untracked non-ignored file blocks with a bounded report (count
120
+ plus top directories, never a path dump), and an ignored entry is deletable
121
+ scratch. One hardcoded exception: an `.env*` file is deletable only when it is
122
+ byte-identical to the main checkout's copy at the same path — otherwise the
123
+ refusal names the exact file. An ignored symlink is unlinked, never followed,
124
+ and only while its target stays inside the worktree: an absolute, escaping,
125
+ dangling, or since-changed target keeps the worktree and names the link. Make
126
+ something deletable by ignoring it; there is no pattern list to configure.
127
+
128
+ Branch retirement is authorized, never assumed. A branch that is an ancestor of
129
+ the **freshly fetched** integration branch is deleted with `-d`; a fetch that
130
+ fails stops instead of trusting a stale ancestry check. Otherwise the platform's
131
+ own record decides: exactly one pull request matching the full tuple — this
132
+ repository on both sides (no fork heads), this head ref, the configured base
133
+ ref, merged — whose head SHA still equals the branch tip re-read immediately
134
+ before the deletion, authorizes the force delete. Zero matches, several matches,
135
+ an open PR on the same head, a tip that moved in between, or no platform access
136
+ at all keep the branch and report why (`branch_authority` in the report; a
137
+ degraded run says so instead of implying the platform agreed). A reused head ref
138
+ resolves to several pull requests, so the head SHA carries the uniqueness, not
139
+ the ref — `land --pr <n>` names the pull request to check when that record is
140
+ ambiguous. `--pr` selects which pull request is validated; it never skips the
141
+ validation.
142
+
143
+ Two refusals name a state landing cannot repair for you: a **detached HEAD**
144
+ (attach a branch in that worktree first) and an **unborn branch** (make the
145
+ first commit first).
146
+
147
+ Step 5f gives the census freshness verdict a session-end home. It reads
148
+ `drift-guard.py --census-status` **for the main checkout** — the tree the next
149
+ session starts from — because a census describes the tree it was scanned in: a
150
+ refresh committed inside a worktree is visible in that one working tree only, so
151
+ a worktree-green verdict must never stand in for a stale main checkout. `current`
152
+ and `no_census` leave no trace at all; only `refresh_required` speaks, as a
153
+ `census` block in the report that names the verdict, its reasons, the **evaluated
154
+ checkout**, and the recovery route — run `$census-update` there and land the
155
+ refresh as a dedicated pull request of its own, never a census file mirrored
156
+ between checkouts. It is a finding, never a gate: topology drift is repo-wide and
157
+ usually not caused by the PR at hand, so the landing completes regardless, and a
158
+ census step that cannot answer degrades to one warning. Opt in with
159
+ `wrapup.censusTrackingIssue` in the board profile to also open one
160
+ marker-identified tracking issue — a later session updates that same issue
161
+ instead of minting a duplicate, and an ambiguous or unreachable lookup writes
162
+ nothing and says why.
163
+
164
+ The dev-server kill is `.dev-ports`-scoped and never signals on doubt: only a
165
+ listener on a port this worktree declares, whose working directory is inside
166
+ it, is signalled — pinned by `pidfd` so a recycled PID cannot be hit. Anything
167
+ else on those ports is a STOP naming the process, not a kill.
105
168
 
106
- STOP diagnose in the main conversation, fix, re-run `land` (an already-merged PR resumes at teardown).
169
+ ### 6 · Post-merge (agent)
170
+ - **Sibling propagation:** for each `drift_markers` entry in the land report, append the note to the target issue's `vor_bau` section + re-stamp its `plan_revision`. Log-based markers → **write directly, then show what was written where** (mandatory report — visibility moved from a pre-gate into the report, decision 2026-07-06); fallback candidates the user hasn't confirmed yet → confirm first. Program context widens the target set to unbuilt wave-stubs/leaves and the Program-PRD itself — same append-only mechanism. **Exception:** appends to the Program-PRD or unbuilt wave-stubs do **not** re-stamp `plan_revision` — that stays reserved for structural wave-plan edits via the `to-waves` escalation path; a mere drift note must not stale-block published stubs.
171
+ - **Anchor close:** report says `anchor_complete: true` → `gh issue close <anchor> -c "Wave complete — all slices merged via PR #<pr>."` and verify board status Done. The guard keeps anchors away from every auto-close — this verified close is the only close path; without it the anchor stays silently open after the last slice. **Then re-run the upward propagation**: the land-time `program-sync` ran BEFORE this close, so on a wave-completing slice the Wellenplan still shows 🔄 and the Phasen-Gate stays unchecked — after the board shows Done, run `python3 scripts/board-sync.py program-sync <program-prd#>` once more (the report's `program_sync.program` names it; skip when the report says the parent is not a program). Board auto-rules can lag the close (Close→Done race) — verify Done first, that's what the token reads.
172
+ - **Report**, concise, from the land JSON: PR merged · issue close (auto/manual) · worktree removed · branch deleted · sweep counts local/remote · anchor synced + complete/pending · program propagation (`program_sync`: Wellenplan refreshed / gates checked / skipped) · propagation writes (what → where) · census finding when the report carries one (verdict + evaluated checkout + recovery route + tracking issue; silent otherwise) · `main` at `<sha>`.
173
+
174
+ <!-- readiness:block deployReport -->
175
+ - **Deploy-aware report:** read the coherent `## Prod` block; before merging,
176
+ state the configured deploy trigger and expected outcome. After merge, report
177
+ the configured target and its actual known state. Do not claim a deployment
178
+ is running or live unless the configured trigger and observed evidence prove
179
+ it; keep unknown timing explicit.
180
+ <!-- readiness:end -->
107
181
 
108
- Before merge, the committed worktree policy only nominates exact landing
109
- evidence. After merge, cleanup reloads `docs/agents/workflow-capabilities.json`
110
- from canonical `origin/main`; only the identical merged, attempt-bound scratch
111
- and generator policy authorizes each evidence path and deletion. A mismatch is
112
- a hard STOP that preserves every file—never bypass it with the unmerged branch
113
- profile.
182
+ ## Content route durable content without a worktree
114
183
 
115
- Landing provenance has one explicit relinquish route. If the STOP names an
116
- unfinished or drifted landing attempt and the ambiguous files cannot be restored
117
- to their frozen identities, run:
184
+ **Explicit invocation only, never a fallback from the flow above.** Use it when `$wrapup` or `/wrapup` runs in the **main checkout on a protected branch** and the session produced durable content — a decision record, a glossary update, a research note — with no worktree and no slice. A session that has a worktree always takes the flow above. Authorization is unchanged: the user's direct invocation, nothing else.
118
185
 
186
+ ### C1 · Infer (read-only)
119
187
  ```bash
120
- python3 scripts/wrapup-land.py land --branch "<branch>" --abandon-unfinished-attempt
188
+ python3 scripts/wrapup-land.py content-claim
121
189
  ```
190
+ Reports every dirty path that could be durable content, each with the blob hash it carries **right now**, plus `unclaimable` — deletions, renames, symlinks, `.env*` — named instead of hidden. Ignored paths are scratch and never appear. A dirty tree too large to reason about stops with a bounded summary (count plus top directories), never a path dump.
122
191
 
123
- This archives the started or frozen attempt receipt only. It deletes and claims
124
- no files, works even when the older creation baseline is missing, and returns
125
- before push, PR, or merge. The next `land` conservatively protects every current
126
- matching path; classify or move those blockers first. Do not use relinquish for
127
- an exact unchanged frozen attempt: a normal retry validates that evidence and
128
- resumes deterministically.
129
-
130
- An attempt journaled under the superseded v1 contract is **legacy, not
131
- corruption**. The STOP says so explicitly and names the same
132
- `--abandon-unfinished-attempt` archive route; archival stays valid for a v1 and
133
- a v2 receipt even without a creation baseline or a local main profile, and no
134
- generated or consumer file is deleted or claimed on that route.
135
-
136
- If canonical `origin/main` changed its scratch or generator policy *after* the
137
- attempt started, the PR can merge and cleanup then STOPs with `worktree cleanup
138
- policy differs from merged canonical origin/main`. That STOP stays fail-closed
139
- and names its one supported route out:
192
+ ### C2 · Claim (the one gate agent judgment)
193
+ Show the candidates and let the **user confirm an explicit file list**. Inference proposes; the claim decides. Write exactly the confirmed records — `path` and `oid` copied verbatim — to a claim file:
194
+ ```json
195
+ {"claimed": [{"path": "docs/decisions/lifecycle.md", "oid": "<from content-claim>"}]}
196
+ ```
140
197
 
198
+ ### C3 · Land
141
199
  ```bash
142
- python3 scripts/wrapup-land.py land --branch "<branch>" --recover-canonical-cleanup
200
+ python3 scripts/wrapup-land.py content-commit --claim-file /tmp/wrapup-claim.json \
201
+ -m "<commit message>" --type "<branch type>" --slug "<slug>" [--anchor <n>] [--body-file <body>]
143
202
  ```
203
+ The branch name comes from the profile's content branch template (issue-less by construction — a planning session has no issue number); the type is one of the profile's own branch prefixes. One call covers: re-read every claimed path (a path whose content moved since the claim is **dropped and named** in the report, the rest still lands; every claimed path gone → STOP) → `.env*` hard block plus the ordinary secret scan on exactly the diff to be committed → stage the claim into a private index and verify the resulting tree by name **and** object id → collision-check the branch locally **and** on the remote → commit → return the main checkout to the protected branch.
144
204
 
145
- This resumes the teardown of an **already-merged** worktree only. It never reads
146
- the stale worktree candidate policy: it re-reads the merged canonical policy,
147
- requires the branch to already be an ancestor of canonical `origin/main`, and
148
- revalidates each frozen landing identity against that canonical policy before
149
- the ordinary shared assessment and removal run. Evidence the canonical policy no
150
- longer names, a changed identity, and any pre-existing or foreign file are hard
151
- STOPs that delete nothing. Re-running after a successful teardown is a no-op.
152
- The flag is mutually exclusive with `--abandon-unfinished-attempt`.
205
+ Everything not in the claim is a bystander and is never read, staged, or written — including changes the user had already staged. The route has no wholesale staging step to widen, so the ordinary dirty-tree commit cannot be reached from here at all. It never closes an anchor: `--anchor` renders the board profile's `prMarkers.partOf` reference, and a `--body-file` that declares a close keyword is refused. There is no teardown half — no worktree to remove, no branch to retire.
153
206
 
154
- ### 6 · Post-merge (agent)
155
- - **Sibling propagation:** for each `drift_markers` entry in the land report, append the note to the target issue's `vor_bau` section + re-stamp its `plan_revision`. Log-based markers → **write directly, then show what was written where** (mandatory report — visibility moved from a pre-gate into the report, decision 2026-07-06); fallback candidates the user hasn't confirmed yet → confirm first. Program context widens the target set to unbuilt wave-stubs/leaves and the Program-PRD itself — same append-only mechanism. **Exception:** appends to the Program-PRD or unbuilt wave-stubs do **not** re-stamp `plan_revision` — that stays reserved for structural wave-plan edits via the `to-waves` escalation path; a mere drift note must not stale-block published stubs.
156
- - **Anchor close:** report says `anchor_complete: true` → `gh issue close <anchor> -c "Wave complete — all slices merged via PR #<pr>."` and verify board status Done. The guard keeps anchors away from every auto-close — this verified close is the only close path; without it the anchor stays silently open after the last slice. **Then re-run the upward propagation**: the land-time `program-sync` ran BEFORE this close, so on a wave-completing slice the Wellenplan still shows 🔄 and the Phasen-Gate stays unchecked — after the board shows Done, run `python3 scripts/board-sync.py program-sync <program-prd#>` once more (the report's `program_sync.program` names it; skip when the report says the parent is not a program). Board auto-rules can lag the close (Close→Done race) — verify Done first, that's what the token reads.
157
- - **Report**, concise, from the land JSON: PR merged · issue close (auto/manual) · worktree removed · branch deleted · sweep counts local/remote · anchor synced + complete/pending · program propagation (`program_sync`: Wellenplan refreshed / gates checked / skipped) · propagation writes (what → where) · `main` at `<sha>`.
207
+ Then land it like any other branch: `land --branch <branch> --title … --body-file …` finds no worktree and tears nothing down.
158
208
 
159
- <!-- readiness:block deployReport -->
160
- - **Deploy-aware report:** read the coherent `## Prod` block; before merging,
161
- state the configured deploy trigger and expected outcome. After merge, report
162
- the configured target and its actual known state. Do not claim a deployment
163
- is running or live unless the configured trigger and observed evidence prove
164
- it; keep unknown timing explicit.
165
- <!-- readiness:end -->
209
+ STOPs name their cause and force nothing: a claimed `.env*` or ignored path, a claim whose every path drifted, a secret in the claimed content, a branch that already exists locally or on the remote, and a **blocked return switch** — a conflicting checkout leaves the main checkout on the content branch and says so; the content is safe in the commit, and nothing is stashed or forced.
166
210
 
167
211
  ## Out of scope
168
212
  - Live-verify / DoD: must happen **before** `$wrapup` or `/wrapup` — this skill lands, it does not verify.
@@ -52,7 +52,9 @@ For a cross-cutting plan, run `python3 .claude/hooks/drift-guard.py --census-sta
52
52
 
53
53
  ## Plan-lock — writing PLAN.md
54
54
 
55
- Once all decisions are made (plan locked, before sign-off/handoff) and the session runs in a **worktree** write the locked plan as `PLAN.md` to the worktree root. `PLAN.md` is **expected** to be ignored by git so it never travels over git — the kit never edits your `.gitignore` by itself, but `/setup-workflow` offers to add that rule (consistent with CLAUDE.md "plan inside the worktree"). This way the locked plan survives a session cut and `to-prd` finds its default source. Continuing same-session work **without** a worktree stays allowed (conversation = source); but for a deliberate **session cut** before `to-prd`, `PLAN.md` is mandatory. (The `-codex` variant already writes `PLAN.md` anyway.)
55
+ Once all decisions are made (plan locked, before sign-off/handoff) write the locked plan as `PLAN.md` **where the session already runs**. Planning creates no worktree: a worktree isolates a build, so it belongs to the implementing session, which creates it when the build starts. `PLAN.md` is **expected** to be ignored by git so it never travels over git — the kit never edits your `.gitignore` by itself, but `/setup-workflow` offers to add that rule. Being ignored is also what makes it scratch: the repository has declared it not-work, so it is deletable at teardown and needs no cleanup step of its own. This way the locked plan survives a session cut and `to-prd` finds its default source. Continuing same-session work stays allowed (conversation = source); but for a deliberate **session cut** before `to-prd`, `PLAN.md` is mandatory. (The `-codex` variant already writes `PLAN.md` anyway.)
56
+
57
+ **Durable output is the opposite case.** Domain-model or glossary edits, decision records and research notes this grill produced are **not** scratch — they are ordinary work and have to reach a commit. Land them with `$wrapup`: a planning session with no worktree takes its Content route, which claims an explicitly confirmed file list and opens the ordinary PR, with no teardown half. Never leave them behind as an uncommitted session leftover.
56
58
 
57
59
  ## Re-grill reconcile — execute-ready (Wave 26)
58
60
 
@@ -49,7 +49,9 @@ For a cross-cutting plan, run `python3 .claude/hooks/drift-guard.py --census-sta
49
49
 
50
50
  When the decision tree is resolved and we're aligned, **write the agreed plan to `PLAN.md`** in this structure, then move to Act 2:
51
51
 
52
- > **Where to write it:** `PLAN.md` + `PLAN-REVIEW-LOG.md` are per-session scratch — write them in the working directory the implementing session will actually use, and invoke the wrapper from that directory. A project may gitignore these files, so don't rely on git to carry them across checkouts/worktrees. In worktree-based repos, create the issue worktree BEFORE this write and plan inside it.
52
+ > **Where to write it:** `PLAN.md` + `PLAN-REVIEW-LOG.md` are per-session scratch — write them where this session already runs, and invoke the wrapper from that directory. Planning creates no worktree: a worktree isolates a build, so it belongs to the implementing session, which creates it when the build starts. A project may gitignore these files, so don't rely on git to carry them across checkouts/worktrees; being ignored is also what makes them scratch, deletable at teardown and needing no cleanup step of their own.
53
+ >
54
+ > **Durable output is the opposite case:** decision records, glossary edits and research notes this grill produced are ordinary work and have to reach a commit. Land them with `$wrapup` — a planning session with no worktree takes its Content route, which claims an explicitly confirmed file list and opens the ordinary PR, with no teardown half. Never leave them behind as an uncommitted session leftover.
53
55
 
54
56
  ```markdown
55
57
  # Plan: <task>