diff --git a/docs/implementation.md b/docs/implementation.md index 5b9965c..daa3b3c 100644 --- a/docs/implementation.md +++ b/docs/implementation.md @@ -20,6 +20,8 @@ Three execution modes control how much human oversight the AI receives during im All task groups are pre-planned in parallel (one planner subagent per group produces `plans/group-N.md`), the adversarial-thinker challenges the plan batch, and an execution schedule of parallel **waves** is derived — groups share a wave only when they have no dependency on each other and disjoint file sets. You approve the batch and schedule, then execution runs with no human intervention. The main conversation acts as an **orchestrator**: each group is executed by a fresh executor subagent with a clean context; the orchestrator re-runs the group's tests itself, dispatches the implementation-reviewer + test-verifier pair in parallel, drives a bounded fix cycle on blocking findings (max 2 rounds, then it stops and asks you), and commits — one atomic commit per group. +Committing is a gate, not a formality: a group is not complete until its commit exists, and the next wave is not dispatched while the current wave's work is uncommitted. Each wave starts from a clean working tree so every dirty path afterwards is attributable to a group in that wave; in a parallel wave the orchestrator stages each group's paths explicitly from the manifest its executor reported, never the whole tree, so concurrent groups still land as separate atomic commits. + ``` plan G1..G4 (parallel) → adversarial challenge → approve batch + waves Wave 1 G1 ⇒ executor → verify pair → commit diff --git a/docs/workflow.md b/docs/workflow.md index e188b60..3122800 100644 --- a/docs/workflow.md +++ b/docs/workflow.md @@ -33,7 +33,7 @@ Interactive Q&A session to gather requirements, then formalizes into a structure ### Step 2: Scope (`/lead-dev-os:step2-scope-tasks`) -Breaks the spec into task groups with explicit context directives. Groups follow an explicit strategy recorded in `tasks.md`: **vertical slices** (preferred — each group a thin end-to-end increment that's demoable on its own and parallelizable during implementation) or **layers** (Database → API → Frontend, when the data model is the hard part). Each task group declares which files from `agents-context/` to load before executing, and reads as a complete user story — a plain-language goal and "done when" definition that a non-technical stakeholder can understand and verify. Produces `tasks.md` with atomic, implementable work items, including an **Execution Waves** map of which groups can safely run in parallel during implementation (no mutual dependencies, disjoint file sets). +Breaks the spec into task groups with explicit context directives. Groups follow an explicit strategy recorded in `tasks.md`: **vertical slices** (preferred — each group a thin end-to-end increment that's demoable on its own and parallelizable during implementation) or **layers** (Database → API → Frontend, when the data model is the hard part). Each task group declares which files from `agents-context/` to load before executing, and reads as a complete user story — a plain-language goal and "done when" definition that a non-technical stakeholder can understand and verify. Produces `tasks.md` with atomic, implementable work items, including an **Execution Waves** map of which groups can safely run in parallel during implementation (no mutual dependencies, disjoint file sets). Disjointness is judged across the test surface as well as the source surface — shared test suites are the usual reason a schedule that looks parallel turns out not to be — and a file-ownership rule names the single owning group for anything two groups would otherwise both edit. ### Step 3: Implement (`/lead-dev-os:step3-implement-tasks`) diff --git a/lead-dev-os/.claude-plugin/plugin.json b/lead-dev-os/.claude-plugin/plugin.json index a3bf278..7792633 100644 --- a/lead-dev-os/.claude-plugin/plugin.json +++ b/lead-dev-os/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "lead-dev-os", - "version": "1.1.0", + "version": "1.2.0", "description": "Spec & context-driven framework for Claude Code development. Structured skills for product planning, spec writing, task scoping, and context-aware implementation.", "author": { "name": "CaptainMe-AI", diff --git a/lead-dev-os/skills/step2-scope-tasks/SKILL.md b/lead-dev-os/skills/step2-scope-tasks/SKILL.md index d10819b..dcdaf60 100644 --- a/lead-dev-os/skills/step2-scope-tasks/SKILL.md +++ b/lead-dev-os/skills/step2-scope-tasks/SKILL.md @@ -42,6 +42,13 @@ This skill does not write code or implementation plans — it produces `tasks.md feature flags, cross-cutting concerns) - Contention hot spots: files that several parts of the feature will all need to touch (these force sequential work) + - Shared test surface: pre-existing test files that assert + project-wide or cross-surface invariants — site-wide sweeps, + snapshot files, shared fixtures and test-utils — naming each one + and what it asserts. Say which of them this feature's changes will + invalidate. These are the most common cause of false parallelism: + every group writes its own new tests, but they all end up repairing + assertions in the same few shared suites. Do not propose a design — just report what exists. ``` @@ -60,6 +67,14 @@ This skill does not write code or implementation plans — it produces `tasks.md Whichever strategy you choose, keep each group's `Dependencies:` list minimal and honest — over-declared dependencies serialize execution for no reason. Use the research reports' contention hot spots when carving groups: if two candidate slices would both rewrite the same few files, either merge them or declare the dependency, rather than pretending they're parallel. +**Carve against the test surface, not just the source surface.** Slices usually are disjoint in source and still collide in tests, because each one invalidates assertions in the same project-wide suite. A wave declared parallel on source files alone gets serialized later by `/lead-dev-os:step3-implement-tasks`, which validates disjointness against the real plans — so the contention has to be resolved here, while the groups are still being carved. New tests never contend (each group writes its own new test file); contention comes entirely from **repairing stale assertions in pre-existing shared suites**. For each shared suite the research reports flagged, pick a resolution in this order: + +1. **Split the suite** along the boundaries the groups already have (per-surface files), so each group owns a file outright. Best outcome — do this whenever the suite's sections separate cleanly. Make the split its own subtask in the earliest group that touches it. +2. **Give the suite a single owner group.** Every assertion repair in that file belongs to the owner; any other group that needs one declares a dependency on the owner and lands in a later wave. +3. **Serialize the contending groups** into different waves. Honest, but the most expensive — use it when neither of the above fits. + +Record the outcome as a **file-ownership rule** in the Overview: which groups exclusively own which shared source files, shared test suites, fixtures, and test-utils. Groups then treat files they don't own as read-only. Files under `agents-context/` are exempt — they never contend, because parallel executors don't write them at all (`/lead-dev-os:step3-implement-tasks` applies each group's proposed context edits itself at commit time). + Each task group uses **hierarchical numbered subtasks**. The parent task (N.0) is the group's completion goal. Subtasks (N.1, N.2, ...) are the steps to achieve it. For each task group (except the final Testing group), follow a **test-first approach**: @@ -145,12 +160,12 @@ If a relevant concept or standard file does NOT yet exist, the directive should - Groups must have explicit **dependency ordering** - Context directives reference **general guidance, not code** — concept files describe approaches, conventions, and decision rationale, never code snippets - The **final group is always "Test Review & Gap Analysis"** — reviews previous tests, fills critical gaps (up to 10 additional tests), runs feature-specific tests, then runs the full test suite ONCE as a final backstop (fix new failures, report pre-existing ones) -- Include an **Execution Order** section at the end listing the recommended implementation sequence, with an **Execution Waves** subsection: waves of groups that can run in parallel during `/lead-dev-os:step3-implement-tasks`. Groups share a wave only when they have no dependency on each other (direct or transitive) AND their expected file sets are disjoint (per the research reports and contention hot spots). When every group depends on the previous one (e.g. layers), say so — one group per wave is an honest answer -- Include an **Overview** section at the top with total task count +- Include an **Execution Order** section at the end listing the recommended implementation sequence, with an **Execution Waves** subsection: waves of groups that can run in parallel during `/lead-dev-os:step3-implement-tasks`. Groups share a wave only when they have no dependency on each other (direct or transitive) AND their expected file sets are disjoint (per the research reports and contention hot spots). **File sets include test files** — new test files, pre-existing shared suites the group will repair, fixtures, and test-utils — not just source files; a wave justified on source files alone is the standard way a parallel schedule collapses at execution time. Files under `agents-context/` don't count toward disjointness. State the per-wave justification in terms of both surfaces, and cite the file-ownership rule for any shared file involved. When every group depends on the previous one (e.g. layers), say so — one group per wave is an honest answer +- Include an **Overview** section at the top with total task count, the grouping strategy and its rationale, and — when any shared source file, test suite, fixture, or test-util is touched by more than one group — a **file-ownership rule** naming the single owning group for each ### Phase 4: Self-check, Review & Save -Before presenting the result, verify `tasks.md` against the Rules for Task Groups above — every group has description, User Story, Done-when block, context directives, honest Dependencies, test-first subtasks, and Acceptance Criteria; the final group is Test Review & Gap Analysis; Overview records the grouping strategy; Execution Order includes the Execution Waves subsection. Fix any gap before showing the file. +Before presenting the result, verify `tasks.md` against the Rules for Task Groups above — every group has description, User Story, Done-when block, context directives, honest Dependencies, test-first subtasks, and Acceptance Criteria; the final group is Test Review & Gap Analysis; Overview records the grouping strategy; Execution Order includes the Execution Waves subsection, and every wave holding 2+ groups is justified across both the source and the test surface. Fix any gap before showing the file. Display the following message to the user: diff --git a/lead-dev-os/skills/step2-scope-tasks/template.md b/lead-dev-os/skills/step2-scope-tasks/template.md index e81e123..94bb24c 100644 --- a/lead-dev-os/skills/step2-scope-tasks/template.md +++ b/lead-dev-os/skills/step2-scope-tasks/template.md @@ -10,6 +10,8 @@ Grouping strategy: [Vertical slices | Layers] — [one-line rationale] [brief summary of the task] +**File-ownership rule (keeps waves parallel-safe):** [Include only when a shared file is touched by more than one group. Name the single owning group for each shared source file, test suite, fixture, and test-util — e.g. "`lib/shared-cta.ts` and `components/Nav.tsx` belong to Group 1 only. The site-wide `invariants.test.ts` suite belongs to Group 4 only; other groups that need an assertion changed there depend on Group 4 rather than editing it." Groups treat files they don't own as read-only. Omit this block entirely when nothing is shared.] + ## Context Management ### Before Starting Each Task Group @@ -216,10 +218,11 @@ Recommended implementation sequence: ### Execution Waves -Groups in the same wave have no mutual dependencies and disjoint expected file sets — `/lead-dev-os:step3-implement-tasks` may run them in parallel after validating against the actual plans: +Groups in the same wave have no mutual dependencies and disjoint expected file sets — `/lead-dev-os:step3-implement-tasks` may run them in parallel after validating against the actual plans. File sets cover the test surface as well as the source surface: new test files, pre-existing shared suites the group will repair, fixtures, and test-utils. Files under `agents-context/` are exempt — parallel executors never write them. - Wave 1: Task Group 1 -- Wave 2: Task Group 2, Task Group 3 — [why they're independent, e.g. "no shared files: Group 2 touches API only, Group 3 touches UI only"] +- Wave 2: Task Group 2, Task Group 3 — [why they're independent on BOTH surfaces, e.g. "source: Group 2 touches API only, Group 3 touches UI only. Tests: each owns its own new suite; neither repairs a shared suite — `[shared-suite]` is owned by Group N per the file-ownership rule"] - Wave 3: Task Group 4 (Test Review & Gap Analysis — always last, always alone) [If groups form a strict chain (e.g. layers strategy), list one group per wave and say so.] +[If a shared test suite forced two otherwise-independent groups into different waves, name the suite and say why it wasn't split or assigned an owner.] diff --git a/lead-dev-os/skills/step3-implement-tasks/SKILL.md b/lead-dev-os/skills/step3-implement-tasks/SKILL.md index 244e684..dc07090 100644 --- a/lead-dev-os/skills/step3-implement-tasks/SKILL.md +++ b/lead-dev-os/skills/step3-implement-tasks/SKILL.md @@ -32,7 +32,8 @@ Shared procedures used by more than one step: ## Hard rules (all modes, all steps) -- **Executor subagents never commit** — the orchestrator commits after verifying each group's work. When groups ran in parallel, stage each group's files separately so each group still gets its own atomic commit. +- **A task group is not complete until it is committed.** In orchestrated execution the orchestrator commits each group the moment it passes verification — never batched at the end of a wave or the end of the run, and never handed back to the user to do. An uncommitted tree at the end of an A-mode run is a failed run. +- **Executor subagents never commit or stage** — the orchestrator commits after verifying each group's work. When groups ran in parallel, stage each group's files explicitly (never `git add -A`, `git add .`, or `git commit -a`) so each group still gets its own atomic commit, and never dispatch the next wave while the current wave's work is uncommitted. - **Never delete tests, weaken assertions, skip migrations, or use `--no-verify`** to get to green — in your own work or by accepting it from a subagent. Surface the failure instead. - **Bounded retries everywhere.** Test-failure fixes: 2 attempts. Verification fix cycles: 2 rounds. After the limit, stop and report — the user would rather debug a stuck group with you than inherit silently disabled tests. - **Check off tasks in `tasks.md` as each completes**, not in a batch at the end. This protects progress if the session is interrupted. Exception: executors running in a parallel wave never write `tasks.md` (or `agents-context/`) — they report completions via `plans/group-N-updates.md` and the orchestrator checks the boxes at commit time, so concurrent groups can't clobber each other's bookkeeping. diff --git a/lead-dev-os/skills/step3-implement-tasks/steps/execute-direct.md b/lead-dev-os/skills/step3-implement-tasks/steps/execute-direct.md index 8dee547..7b67d74 100644 --- a/lead-dev-os/skills/step3-implement-tasks/steps/execute-direct.md +++ b/lead-dev-os/skills/step3-implement-tasks/steps/execute-direct.md @@ -55,7 +55,7 @@ Atomic-commit policy: - **Default: one commit per task group.** The commit message describes what the group shipped (not how) and references the spec folder name. - **Optional sub-commits:** if a group has natural sub-units (e.g. a "primitives" sub-task that lands cleanly on its own, then "integration" on top), commit each sub-unit separately. Use judgment — if you can't summarize a sub-commit in one clean line, it isn't ready as its own commit. -- **Don't sweep up unrelated changes.** If the user has uncommitted edits in files outside this group's scope, ask before staging anything. +- **Don't sweep up unrelated changes.** Stage this group's paths, not the whole tree. If the user has pre-existing uncommitted edits in files outside this group's scope, ask what to do with them — but that question never postpones this group's commit: stage the group's own paths and commit them regardless. In **L** mode you may skip the auto-commit and let the user commit manually after the review gate. diff --git a/lead-dev-os/skills/step3-implement-tasks/steps/execute-orchestrated.md b/lead-dev-os/skills/step3-implement-tasks/steps/execute-orchestrated.md index 3b64847..563c269 100644 --- a/lead-dev-os/skills/step3-implement-tasks/steps/execute-orchestrated.md +++ b/lead-dev-os/skills/step3-implement-tasks/steps/execute-orchestrated.md @@ -2,30 +2,105 @@ *Applies to mode A, and mode H before the checkpoint.* -The main conversation acts as an orchestrator: each group is executed by a fresh executor subagent, verified by the verification pair, then committed by the orchestrator. This keeps the main context small regardless of how many groups the feature has — group 6 gets the same quality of attention as group 1. +The main conversation acts as an orchestrator: each group is executed by a fresh executor subagent, verified by the verification pair, then **committed by the orchestrator before the wave can close**. This keeps the main context small regardless of how many groups the feature has — group 6 gets the same quality of attention as group 1. -Work through the approved execution schedule wave by wave: +## The commit invariant -1. **Parallel dispatch — one executor subagent per group in the current wave**, all in a single tool-call batch (`subagent_type: "general-purpose"`), using the prompt template below. When the wave holds 2+ groups, append the **parallel-wave addendum** (below the prompt template) to each executor's prompt — the plans' "File operations" lists are disjoint, but `tasks.md` and `agents-context/` are shared by every group, so concurrent executors must not write them. Each executor starts with a fresh context and reads everything it needs from disk — never assume it inherits knowledge from this conversation. Dispatch a wave only when every group it depends on has been committed. If anything since planning has cast doubt on a wave's independence (a plan amended mid-run, drift reported by an earlier executor), re-check the two wave conditions — no dependency, disjoint file sets — and serialize when in doubt. +Read this before dispatching anything and hold it for the whole run. Committing is not the bookkeeping at the end of a group — it is the step that makes the group exist. + +- **A group is not complete until its commit exists.** Executors never commit; the orchestrator does. A group whose work sits uncommitted in the working tree is an unfinished group, however green its tests are. +- **Commit each group the moment it passes verification** — not at the end of the wave, not at the end of the run, not when the user asks. Deferred commits are lost commits: the run gets interrupted, the context fills, or a later group edits the same file, and the group boundary is gone for good. +- **Never batch groups into one commit**, and never let a group's changes ride along in another group's commit. +- **Never dispatch a wave while the previous wave's work is uncommitted.** `git status --porcelain` gates both ends of every wave (below). +- **Never `git add -A`, `git add .`, or `git commit -a` in a parallel wave** — they sweep up the sibling groups still in flight. Never `--no-verify`. + +There is no mode of this workflow in which the orchestrator hands committing back to the user. In A mode nobody is watching; an uncommitted tree at the end of the run is a failed run. + +## Before each wave — establish a clean baseline + +Run `git status --porcelain`. **It must be empty before a wave is dispatched.** + +- If it is empty: every path that turns up dirty from here on was produced by this wave's executors, and attribution is unambiguous. +- If it is not empty: this is the only place the "don't sweep up unrelated changes" rule applies. Show the user the dirty paths and ask whether to commit them, stash them, or carry them as out-of-scope. If they are carried, record that exact path list once as the **run baseline** and treat those paths as invisible for the rest of the run — never stage them, and subtract them from every later `git status` check instead of re-asking each wave. + +Never start a wave from a tree you cannot account for. Attribution after the fact is guesswork, and guesswork is what makes an orchestrator defer the commit. + +## Wave loop + +Work through the approved execution schedule wave by wave. Dispatch a wave only when every group it depends on has been **committed** (not merely finished). + +1. **Parallel dispatch — one executor subagent per group in the current wave**, all in a single tool-call batch (`subagent_type: "general-purpose"`), using the prompt template below. When the wave holds 2+ groups, append the **parallel-wave addendum** (below the prompt template) to each executor's prompt — the plans' "File operations" lists are disjoint, but `tasks.md` and `agents-context/` are shared by every group, so concurrent executors must not write them. Each executor starts with a fresh context and reads everything it needs from disk — never assume it inherits knowledge from this conversation. If anything since planning has cast doubt on a wave's independence (a plan amended mid-run, drift reported by an earlier executor), re-check the two wave conditions — no dependency, disjoint file sets — and serialize when in doubt. 2. **Verify — trust but verify.** When an executor returns, run the group's verification command from `plans/group-.md` yourself. Do not take the executor's report at face value. 3. **Dispatch the verification pair** — implementation-reviewer and test-verifier in parallel, per [../shared/verification-agents.md](../shared/verification-agents.md). On blocking findings, run that file's bounded fix cycle (redispatch an executor scoped to the findings; max 2 rounds). Advisory findings go into the group report. -4. **Review the diff** briefly yourself for scope creep, deleted tests, or weakened assertions — the reviewer checks this too, but the orchestrator owns the commit. +4. **Review the diff** briefly yourself for scope creep, deleted tests, or weakened assertions — the reviewer checks this too, but the orchestrator owns the commit. Scope the diff to the group's paths: `git diff HEAD -- `. -5. **Commit.** Executors never commit — the orchestrator commits after verifying. When groups ran in parallel: first apply the group's `plans/group--updates.md` yourself — check off its completed tasks in `tasks.md`, create/update the proposed concept files, and keep `agents-context/README.md` in sync — then stage the plan's "File operations" list **plus** those bookkeeping changes, so each group still gets its own atomic commit that includes its checkboxes and context updates. Commit message: what the group shipped (not how), referencing the spec folder name. Don't sweep up unrelated changes — if the user has uncommitted edits outside this group's scope, ask before staging anything. +5. **Commit — immediately, before touching the next group.** Follow the [commit procedure](#commit-procedure) below. Do not queue the commit, do not move on to a sibling group's verification first, and do not proceed at all if the commit fails: a failed commit is a blocker, and blockers stop the run. -6. **Report and continue:** - - Group N complete +6. **Report the group**, including its commit receipt: + - Group N complete — **committed as `` ``** - Tests written / passing - Verification verdicts (reviewer, test-verifier) + advisory findings - Concept files created or updated - - Next wave queued + - Next group / next wave queued + + Steps 2–6 run per group. In a parallel wave, run them for each returned executor in turn, so each group is committed before the next one is processed. + +7. **Close the wave.** After the last group in the wave is committed, run `git status --porcelain` again. It must be empty (or equal to the run baseline). See [unclaimed paths](#unclaimed-paths) if it isn't. Only then dispatch the next wave. In H mode, when the checkpoint group is reached, switch to direct execution with L behavior. + +If an executor reports a blocker, plan-invalidating drift, or exhausted retries, stop and apply the error-handling rules — surface it to the user; don't redispatch blindly. Groups already committed stay committed; report where the run stopped. + +## Commit procedure + +### Solo-group wave + +The wave started from a clean baseline and only one executor ran, so the entire diff is that group's work. Stage it whole (excluding any run-baseline paths), then commit: + +```bash +git add -A # or: git add -- , if a run baseline is being carried +git status --short # confirm nothing baseline-owned got staged +git commit -m "" +git log -1 --oneline # receipt for the group report +``` + +### Parallel wave + +The tree holds every group in the wave at once, so staging must be explicit — `git add` takes whole files, and there is no partial-credit staging that would make a mixed file safe. + +1. **Apply the group's bookkeeping yourself** from `plans/group--updates.md`: check off its completed tasks in `tasks.md`, create/update the proposed concept files, and keep `agents-context/README.md` in sync. Executors in a parallel wave never write these, so they are the orchestrator's edits. + +2. **Stage exactly this group's paths** — the "Files changed" manifest from `plans/group--updates.md` (which supersedes the plan's "File operations" list; executors create files the plan didn't predict), plus the bookkeeping files you just edited, plus `plans/group--updates.md` and `plans/group-.md` itself if the executor amended it: + + ```bash + git add -- ... + git diff --cached --name-only # must equal the intended list, nothing more + ``` + +3. **Commit**, then take the receipt: + + ```bash + git commit -m "" + git log -1 --oneline + ``` + +`git status` will still show the sibling groups' work after this commit. That is expected and is **not** a reason to withhold the commit — those paths belong to groups that have not been processed yet, and they are accounted for by the wave-close check. + +### If two groups touched the same file + +The wave conditions were supposed to prevent this, so treat it as a scheduling failure, not a staging puzzle. Do not guess which hunks belong to whom and do not `git add -p` your way out of it. Commit the group that owns the file per `tasks.md`'s file-ownership rules (its change lands whole), then tell the user which file was contended and which group's edits rode along in the other group's commit, so the schedule can be fixed for the next run. + +### Commit message + +What the group shipped, not how, referencing the spec folder name and group number — e.g. `feat(website): retire the waitlist funnel` with a body naming `Group 2 of `. Follow the project's commit conventions from `agents-context/` when it has them. + +### Unclaimed paths - Then dispatch the next wave. In H mode, when the checkpoint group is reached, switch to direct execution with L behavior. +At wave close, any path still dirty that no group's manifest claimed was produced by an executor and nearly always belongs to the group that just committed (a test fixture, an amended plan file, a helper the plan didn't list). Do not delete it and do not let it drift into the next group's commit: -If an executor reports a blocker, plan-invalidating drift, or exhausted retries, stop and apply the error-handling rules — surface it to the user; don't redispatch blindly. +- If it clearly belongs to the group whose commit is still `HEAD`: `git add -- && git commit --amend --no-edit`. +- Otherwise: stop and ask the user before the next wave. An unattributable file in the tree means the wave's file sets were not actually disjoint. ## Executor prompt template @@ -62,11 +137,16 @@ Then execute the group: group's "Update after completing" header; keep agents-context/README.md in sync (index entry, Load-When Cheatsheet, cross-references). -Do NOT commit — the orchestrator commits after verifying your work. +Do NOT commit and do NOT stage anything — the orchestrator commits after +verifying your work. Leave your changes in the working tree. Final report (structured): +- Files changed — EXHAUSTIVE list of every repo-relative path you + created, modified, or deleted, one per line, marked create/modify/ + delete. Include test files, fixtures, snapshots, generated files, and + any amendment you made to plans/group-.md. The orchestrator stages + exactly this list; a path you omit does not get committed. - Tests written / passing (counts and file paths) -- Files created / modified / deleted - Concept files created or updated - Plan drift found and how the plan was amended (if any) - Blockers or open questions (if any) @@ -83,12 +163,28 @@ in the same working tree: - Do NOT modify tasks.md or any file under agents-context/ — they are shared with the other groups' executors, and concurrent writes clobber each other. This overrides steps 5 and 6 above. -- Instead, write /plans/group--updates.md with two sections: +- Do NOT run any git command that changes state — no add, commit, stash, + checkout, restore, or clean. Other groups' uncommitted work is in this + tree and you would destroy it. Read-only git (status, diff, log) is + fine. +- Instead, write /plans/group--updates.md with three + sections: 1. Completed tasks — the task numbers from Group N to check off in tasks.md - 2. Context updates — each concept file to create or update, with its - full proposed content, plus the agents-context/README.md entries to - add or refresh (index entry, Load-When Cheatsheet, cross-references) + 2. Context updates — each concept file to create (with its full + proposed content) or update, plus the agents-context/README.md + entries to add or refresh (index entry, Load-When Cheatsheet, + cross-references). For a file that already exists, give + ANCHORED EDITS — the surrounding text to insert after, replace, + or delete — never a full-file rewrite. Another group may be + proposing edits to the same file; anchored edits compose when the + orchestrator applies them one commit after another, and a full-file + rewrite silently discards whatever landed first. + 3. Files changed — the same exhaustive path list as your final report, + one repo-relative path per line. This is what the orchestrator + stages; anything missing from it will not be committed. Include + plans/group--updates.md itself and plans/group-.md if you + amended it. The orchestrator applies this file and commits it together with your group's changes. diff --git a/lead-dev-os/skills/step3-implement-tasks/steps/finalize.md b/lead-dev-os/skills/step3-implement-tasks/steps/finalize.md index 22cea59..55d212f 100644 --- a/lead-dev-os/skills/step3-implement-tasks/steps/finalize.md +++ b/lead-dev-os/skills/step3-implement-tasks/steps/finalize.md @@ -2,15 +2,17 @@ Run after all task groups are complete, regardless of mode. -1. **Adversarial delivery review.** Dispatch the **adversarial-thinker** with the delivery-challenge prompt from [../shared/adversarial-agent.md](../shared/adversarial-agent.md) — a fresh, read-only agent that tries to break the finished feature against the spec. Triage per that file's guidance: fix confirmed, in-scope defects (bounded — max 2 fix rounds, then surface); report the rest to the user with the summary. Run this before the full-suite backstop so any fixes are covered by it. +1. **Confirm every group is committed.** Run `git status --porcelain` and `git log --oneline` over the run. Every completed task group must have its own commit, and the tree must be clean apart from any run baseline the user chose to carry. If a group's work is still sitting in the working tree, commit it now — one commit per group, per the commit procedure in [execute-orchestrated.md](execute-orchestrated.md#commit-procedure) — before running anything below. Do not summarize a run as delivered while its work is uncommitted. -2. **Run the full test suite once** (if the final task group's backstop subtask didn't already). This is the only full-suite run in the workflow. Triage failures: fix NEW failures this feature caused; report pre-existing failures without fixing them. +2. **Adversarial delivery review.** Dispatch the **adversarial-thinker** with the delivery-challenge prompt from [../shared/adversarial-agent.md](../shared/adversarial-agent.md) — a fresh, read-only agent that tries to break the finished feature against the spec. Triage per that file's guidance: fix confirmed, in-scope defects (bounded — max 2 fix rounds, then surface); report the rest to the user with the summary. Run this before the full-suite backstop so any fixes are covered by it. -3. **Verify at runtime.** Tests passing is not the same as the feature working — exercise the feature's primary user flow in the running app where feasible (start the app, hit the endpoint, click through the UI) and confirm the observable behavior matches the spec's acceptance criteria. If runtime verification isn't feasible, say so explicitly rather than skipping silently. +3. **Run the full test suite once** (if the final task group's backstop subtask didn't already). This is the only full-suite run in the workflow. Triage failures: fix NEW failures this feature caused; report pre-existing failures without fixing them. -4. **Confirm every "Acceptance Criteria" block in `tasks.md` is satisfied.** +4. **Verify at runtime.** Tests passing is not the same as the feature working — exercise the feature's primary user flow in the running app where feasible (start the app, hit the endpoint, click through the UI) and confirm the observable behavior matches the spec's acceptance criteria. If runtime verification isn't feasible, say so explicitly rather than skipping silently. -5. **Summarize:** +5. **Confirm every "Acceptance Criteria" block in `tasks.md` is satisfied.** + +6. **Summarize:** - What was built - Adversarial findings — fixed vs. reported - Concept files created or updated during execution diff --git a/lead-dev-os/skills/step3-implement-tasks/steps/pre-plan.md b/lead-dev-os/skills/step3-implement-tasks/steps/pre-plan.md index 207c789..a051c29 100644 --- a/lead-dev-os/skills/step3-implement-tasks/steps/pre-plan.md +++ b/lead-dev-os/skills/step3-implement-tasks/steps/pre-plan.md @@ -47,9 +47,16 @@ Triage its findings per that file's guidance: amend plan files directly for clea Group the incomplete task groups into **waves**. Two or more groups may share a wave only when BOTH hold: - **(a) No dependency** between them, directly or transitively, per the `Dependencies:` headers. -- **(b) Disjoint file sets** per the plans' "File operations" sections — no file appears in two plans in the same wave. +- **(b) Disjoint file sets** per the plans' "File operations" sections — no file appears in two plans in the same wave. Two exclusions, both because parallel executors never write these files: `tasks.md` and everything under `agents-context/`. The orchestrator applies each group's checkboxes and context edits itself at commit time, from `plans/group-N-updates.md`, so they cannot clobber each other. **Do not serialize a wave over a shared concept file** — that is a conflict this workflow has already solved, and counting it costs real parallelism. Everything else counts, including test files: a shared test suite two groups both need to repair is a genuine collision. -Start from the Execution Waves subsection in `tasks.md` if present, then validate it against the actual plans — condition (b) can only be confirmed now that plans exist. If the adversarial-thinker flagged a hidden dependency or file contention, respect the flag. When in doubt, serialize — a serialized group is cheaper than a merge conflict. +Start from the Execution Waves subsection in `tasks.md` if present, then validate it against the actual plans — condition (b) can only be confirmed now that plans exist. If the adversarial-thinker flagged a hidden dependency or file contention, respect the flag. + +When a wave fails only on condition (b), try to fix the contention before serializing: + +- If `tasks.md` carries a **file-ownership rule** naming a single owner for the contended file, amend the non-owner's plan to drop the edit (declaring a dependency on the owner if it genuinely needs it) rather than splitting the wave. +- If the contended file is a shared test suite whose assertions separate cleanly along group boundaries, amending one plan to own the whole file is usually enough. + +Serialize when neither works — a serialized group is cheaper than a merge conflict. Whichever way it resolves, say so in the schedule: name the file, the groups, and why it forced a split. Serialization that isn't explained reads as a dependency and gets copied forward into the next spec. ## 5. Report and wait for "go" diff --git a/tests/test_skill_content.sh b/tests/test_skill_content.sh index d417b29..6250319 100755 --- a/tests/test_skill_content.sh +++ b/tests/test_skill_content.sh @@ -191,6 +191,128 @@ else fail "step3 missing parallel dispatch of independent groups" fi +# --- step3: the per-group commit gate (parallel waves must still commit atomically) --- + +echo "" +echo "step3 per-group commit gate:" + +ORCH_MD="$STEP3_DIR/steps/execute-orchestrated.md" + +if grep -q 'not complete until it is committed' "$STEP3_MD" 2>/dev/null; then + pass "step3 hard rule: a group is not complete until committed" +else + fail "step3 missing 'not complete until committed' hard rule" +fi + +if grep -q 'never dispatch the next wave while the current wave' "$STEP3_MD" 2>/dev/null; then + pass "step3 hard rule: no new wave while the current wave is uncommitted" +else + fail "step3 missing uncommitted-wave dispatch bar" +fi + +if grep -q 'commit invariant' "$ORCH_MD" 2>/dev/null; then + pass "step3 orchestrated execution states the commit invariant up front" +else + fail "step3 orchestrated execution missing the commit invariant section" +fi + +if grep -q 'must be empty before a wave is dispatched' "$ORCH_MD" 2>/dev/null; then + pass "step3 requires a clean git baseline before each wave" +else + fail "step3 missing clean-baseline precondition for waves" +fi + +if grep -q 'git add -A`, `git add .`, or `git commit -a`' "$ORCH_MD" 2>/dev/null; then + pass "step3 forbids tree-wide staging in a parallel wave" +else + fail "step3 missing prohibition on tree-wide staging in parallel waves" +fi + +if grep -q 'git diff --cached --name-only' "$ORCH_MD" 2>/dev/null; then + pass "step3 verifies the staged set before committing a group" +else + fail "step3 missing staged-set verification before commit" +fi + +if grep -q 'committed as' "$ORCH_MD" 2>/dev/null; then + pass "step3 group report carries a commit receipt" +else + fail "step3 group report missing commit receipt" +fi + +if grep -q 'Files changed' "$ORCH_MD" 2>/dev/null; then + pass "step3 executors report an exhaustive changed-file manifest" +else + fail "step3 missing exhaustive changed-file manifest for staging" +fi + +if grep -q 'Close the wave' "$ORCH_MD" 2>/dev/null; then + pass "step3 closes each wave with a dirty-tree check" +else + fail "step3 missing wave-close dirty-tree check" +fi + +if grep -q 'Confirm every group is committed' "$STEP3_DIR/steps/finalize.md" 2>/dev/null; then + pass "step3 finalize verifies every group landed a commit" +else + fail "step3 finalize missing commit-completeness check" +fi + +# --- wave scheduling must account for the test surface, not just source files --- + +echo "" +echo "Wave scheduling across the test surface:" + +STEP2_DIR="$PLUGIN_DIR/skills/step2-scope-tasks" + +if grep -q 'Shared test surface' "$STEP2_DIR/SKILL.md" 2>/dev/null; then + pass "step2 research asks for the shared/cross-cutting test surface" +else + fail "step2 research prompt missing shared test surface" +fi + +if grep -q 'Carve against the test surface' "$STEP2_DIR/SKILL.md" 2>/dev/null; then + pass "step2 carves groups against the test surface too" +else + fail "step2 missing test-surface carving guidance" +fi + +if grep -q 'file-ownership rule' "$STEP2_DIR/SKILL.md" 2>/dev/null; then + pass "step2 records a file-ownership rule for shared files" +else + fail "step2 missing file-ownership rule" +fi + +if grep -q 'File-ownership rule' "$STEP2_DIR/template.md" 2>/dev/null; then + pass "step2 template carries the file-ownership rule block" +else + fail "step2 template missing file-ownership rule block" +fi + +if grep -q 'File sets include test files' "$STEP2_DIR/SKILL.md" 2>/dev/null; then + pass "step2 wave rule counts test files toward disjointness" +else + fail "step2 wave rule ignores test files" +fi + +if grep -q 'Do not serialize a wave over a shared concept file' "$STEP3_DIR/steps/pre-plan.md" 2>/dev/null; then + pass "step3 does not serialize waves over orchestrator-applied context files" +else + fail "step3 still counts agents-context/ toward wave disjointness" +fi + +if grep -q 'ANCHORED EDITS' "$ORCH_MD" 2>/dev/null; then + pass "step3 parallel context updates compose instead of overwriting" +else + fail "step3 parallel context updates risk whole-file overwrite" +fi + +if grep -q 'name the file, the groups, and why it forced a split' "$STEP3_DIR/steps/pre-plan.md" 2>/dev/null; then + pass "step3 explains every serialization in the schedule" +else + fail "step3 serializations go unexplained" +fi + # --- step3: structured shape (orchestrator + steps/ + shared/) --- echo ""