@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.
- package/.agents/skills/grill-me/SKILL.md +3 -1
- package/.agents/skills/grill-with-docs/SKILL.md +3 -1
- package/.agents/skills/kit-update/SKILL.md +9 -11
- package/.agents/skills/orchestrate-wave/SKILL.md +8 -8
- package/.agents/skills/setup-workflow/SKILL.md +20 -18
- package/.agents/skills/setup-workflow/board-sync.md +4 -1
- package/.agents/skills/setup-workflow/workflow-advisories.md +3 -2
- package/.agents/skills/setup-workflow/worktree-lifecycle.md +36 -31
- package/.agents/skills/to-issues/SKILL.md +43 -0
- package/.agents/skills/wrapup/SKILL.md +98 -54
- package/.claude/skills/grill-me/SKILL.md +3 -1
- package/.claude/skills/grill-me-codex/SKILL.md +3 -1
- package/.claude/skills/grill-with-docs/SKILL.md +3 -1
- package/.claude/skills/grill-with-docs-codex/SKILL.md +3 -1
- package/.claude/skills/kit-update/SKILL.md +9 -11
- package/.claude/skills/orchestrate-wave/SKILL.md +8 -8
- package/.claude/skills/setup-workflow/SKILL.md +20 -18
- package/.claude/skills/setup-workflow/board-sync.md +4 -1
- package/.claude/skills/setup-workflow/workflow-advisories.md +3 -2
- package/.claude/skills/setup-workflow/worktree-lifecycle.md +36 -31
- package/.claude/skills/to-issues/SKILL.md +43 -0
- package/.claude/skills/wrapup/SKILL.md +98 -54
- package/README.md +249 -7
- package/agent-workflow-kit.package.json +42 -42
- package/package.json +16 -12
- package/scripts/marker_lib.py +3 -0
- package/scripts/profile_globs.py +26 -45
- package/scripts/release-delta-guard.mjs +26 -9
- package/scripts/worktree-lifecycle/README.md +57 -160
- package/scripts/worktree-lifecycle/capabilities.json +2 -3
- package/scripts/worktree-lifecycle/classify.py +480 -0
- package/scripts/worktree-lifecycle/cleanup.py +9 -29
- package/scripts/worktree-lifecycle/core.py +68 -1429
- package/scripts/worktree-lifecycle/ignore_seed.py +1 -1
- package/scripts/worktree-lifecycle/profile.py +46 -29
- package/scripts/worktree-lifecycle/setup.py +7 -19
- package/scripts/wrapup-land.py +1292 -545
- package/src/consumer-migrations.json +1 -16
- package/src/lib/bundle.mjs +31 -1
- package/docs/adr/0001-consumer-divergence-policy.md +0 -53
- package/docs/adr/0002-capability-gated-orchestration.md +0 -70
- package/docs/adr/0003-kit-core-and-project-extension-lifecycle.md +0 -63
- package/docs/adr/0004-release-intent-is-a-version-tag.md +0 -64
- package/docs/adr/0005-to-issues-is-the-planning-facade.md +0 -42
- package/docs/adr/0006-routing-knowledge-access-and-policy-are-separate.md +0 -95
- package/docs/adr/0007-session-teardown-requires-provenance-bound-ownership.md +0 -88
- package/docs/adr/0008-planning-ignore-rules-are-offered-never-installed.md +0 -84
- package/docs/adr/0009-teardown-authority-is-stateless-repository-classification.md +0 -101
- package/docs/adr/0010-model-roster-replaces-the-optimization-dial.md +0 -87
- package/docs/agents/board-sync.md +0 -74
- package/docs/agents/code-review.md +0 -14
- package/docs/agents/workflow-capabilities.json +0 -28
- package/docs/research/agent-task-taxonomy-benchmark-coverage.md +0 -451
- package/docs/research/benchlm-routing-source.md +0 -198
- package/docs/research/consumer-owned-protocol-files.md +0 -238
- package/docs/research/frontend-agent-benchmarks.md +0 -282
- package/docs/research/model-effort-routing-benchmarks.md +0 -261
- package/docs/research/provider-neutral-agent-routing.md +0 -207
- package/docs/research/wave-152-consumer-acceptance.md +0 -98
- package/docs/research/wave-43-script-hook-census.md +0 -128
- package/scripts/build-kit.mjs +0 -117
- package/scripts/build-kit.test.mjs +0 -207
- package/scripts/census/census.test.mjs +0 -252
- package/scripts/census/state.test.mjs +0 -15
- package/scripts/census/transaction.test.mjs +0 -103
- package/scripts/census-contract.test.mjs +0 -227
- package/scripts/check-kit-staleness.mjs +0 -45
- package/scripts/check-kit-staleness.test.mjs +0 -19
- package/scripts/codex-exec-scenarios/fake-codex.mjs +0 -165
- package/scripts/codex-exec.test.mjs +0 -871
- package/scripts/grill-census-wiring-guard.mjs +0 -87
- package/scripts/grill-census-wiring-guard.test.mjs +0 -107
- package/scripts/kit-release.test.mjs +0 -273
- package/scripts/kit-update-pr.test.mjs +0 -151
- package/scripts/lib/audit-refs.mjs +0 -146
- package/scripts/lib/scrub.mjs +0 -113
- package/scripts/lib/scrub.test.mjs +0 -187
- package/scripts/memory-lifecycle/memory-lifecycle.test.mjs +0 -170
- package/scripts/portability_profile_scan.py +0 -53
- package/scripts/release-delta-guard.test.mjs +0 -174
- package/scripts/release-parity.test.mjs +0 -90
- package/scripts/release-state.test.mjs +0 -360
- package/scripts/test_anchor_table.py +0 -69
- package/scripts/test_board_bootstrap.py +0 -348
- package/scripts/test_board_sync.py +0 -208
- package/scripts/test_board_sync_create_idempotency.py +0 -117
- package/scripts/test_board_sync_wave_title.py +0 -120
- package/scripts/test_census_backstop.py +0 -712
- package/scripts/test_census_forward_contract.py +0 -91
- package/scripts/test_census_update_contract.test.mjs +0 -454
- package/scripts/test_codex_adapter_sync_contract.py +0 -169
- package/scripts/test_dist_kit_smoke.py +0 -220
- package/scripts/test_drift_guard_diagnostics.py +0 -295
- package/scripts/test_issue_claim_contract.py +0 -169
- package/scripts/test_kit_docs_language_census.py +0 -178
- package/scripts/test_marker_lib.py +0 -162
- package/scripts/test_orchestrate_wave_contract.py +0 -381
- package/scripts/test_pr_body_check.py +0 -264
- package/scripts/test_profile_globs.py +0 -280
- package/scripts/test_program_planning_contract.py +0 -133
- package/scripts/test_release_authorization_contract.py +0 -101
- package/scripts/test_render_anchor.py +0 -267
- package/scripts/test_retro_wrapup_contract.py +0 -153
- package/scripts/test_skill_code_review_seed.py +0 -89
- package/scripts/test_skill_codex_exec_lifecycle.py +0 -123
- package/scripts/test_skill_frontmatter_lint.py +0 -234
- package/scripts/test_skill_gh_lint.py +0 -124
- package/scripts/test_skill_language_census.py +0 -254
- package/scripts/test_skill_optional_readiness.py +0 -171
- package/scripts/test_skill_portability_lint.py +0 -866
- package/scripts/test_skill_precommit_template.py +0 -30
- package/scripts/test_skill_publish_audit.py +0 -358
- package/scripts/test_skill_readiness_contract.py +0 -264
- package/scripts/test_skill_readiness_preflight.py +0 -180
- package/scripts/test_skill_required_readiness.py +0 -233
- package/scripts/test_skill_selfcontainment_lint.py +0 -255
- package/scripts/test_skill_setup_workflow_seeds.py +0 -691
- package/scripts/test_skill_stale_name_lint.py +0 -126
- package/scripts/test_skill_surface_refs.py +0 -300
- package/scripts/test_skill_trailing_artifact_lint.py +0 -71
- package/scripts/test_tdd_contract.py +0 -78
- package/scripts/test_worktree_ignore_seed.py +0 -320
- package/scripts/test_worktree_setup_base_guard.py +0 -140
- package/scripts/test_worktree_wrapup_contract.py +0 -1737
- package/scripts/test_wrapup_land.py +0 -428
- 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)
|
|
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)
|
|
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
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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 —
|
|
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
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
|
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.
|
|
145
|
-
4. **Wave worktree**: reuse the planning worktree
|
|
146
|
-
|
|
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
|
|
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`,
|
|
362
|
-
-
|
|
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
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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
|
|
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
|
-
|
|
221
|
-
|
|
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
|
-
|
|
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 —
|
|
456
|
-
|
|
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
|
|
609
|
-
|
|
610
|
-
|
|
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
|
|
82
|
-
|
|
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
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
rules above
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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 —
|
|
127
|
-
|
|
128
|
-
`scripts/profile_globs.py`. There is no
|
|
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
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
|
160
|
-
|
|
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.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
|
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`
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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
|
|
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>
|