From 1720aacf0c65cef140e3a6787ea1de7432032002 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Sun, 19 Jul 2026 07:52:36 -0400 Subject: [PATCH] =?UTF-8?q?feat(#1949):=20=20task=20element?= =?UTF-8?q?=20=E2=80=94=20Design=20by=20Contract=20(#2422)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test(#1949): add failing-first tests for element Red phase for issue #1949 (Design by Contract: element asserted before task execution). Tests assert: - docs/reference/plan-md.md documents the new element - agents/gsd-planner.md @-references planner-preconditions.md and stays under the 49152-char cap (progressive-disclosure requirement) - gsd-core/references/planner-preconditions.md exists and documents the three emission cases mandated by the issue (user_setup / prior-phase artifact / env-var) and the contract triad mapping - agents/gsd-executor.md asserts before task execution and routes unmet preconditions through existing checkpoint machinery - cmdVerifyPlanStructure (behavioral via runGsdTools) accepts plans both with and without — the additive-validation guarantee - Parity assertion: plan-md.md and planner-preconditions.md agree on the canonical tag spelling (DEFECT.GENERATIVE-FIX-DIVERGENCE guard) Most prose-contract assertions are Red until the implementation lands. The behavioral validator assertions pass immediately (regression guards proving the validator already accepts unknown optional tags). * feat(#1949): task element — Design by Contract Add an optional element to in PLAN.md (issue #1949, The Pragmatic Programmer Topic 23). The front-of-task side of the plan contract — preconditions (before) ↔ postconditions (// , after) ↔ invariants (must_haves.truths, across the whole plan). Together with the tracer-bullet proposal (#1945), this closes both ends of the 'outrunning your headlights' failure mode for an autonomous AI executor. Acceptance criteria met: - is an optional element on ; plans that omit it validate unchanged (cmdVerifyPlanStructure checks for presence of required tags, does not reject unknown optional tags). - gsd-executor evaluates the precondition before any other task work. Unmet halts execution with a checkpoint:human-verify and no partial commit; met or absent produces no visible change to execution flow. Unmet is never auto-approved under AUTO_CFG=true — a missing prerequisite is a fact the executor cannot establish on its own. - gsd-planner emits in exactly the three cases the issue mandates: user_setup consumption, prior-phase artifact dependency, and env-var/runtime-config dependency. - Tests cover met, unmet, and absent preconditions plus the additive- validator guarantee. Files: - gsd-core/references/planner-preconditions.md (NEW): full emission rules, the three cases with worked examples, format guidance, anti-patterns, the contract triad mapping, and the executor assertion contract. Progressive disclosure. - agents/gsd-planner.md: slim note in Task Anatomy with @-reference to the new file. To stay under the 49152-char agent-file cap (27-char headroom before this change), the inline and summaries are compressed to one-line pointers — their full rules already live in planner-antipatterns.md, so no content is lost. - agents/gsd-executor.md: new step 0 'Precondition check' in the execute_tasks loop, before the type dispatch, routing unmet through checkpoint_return_format. - docs/reference/plan-md.md: new Preconditions section in the schema reference, with the canonical example and the three emission cases. - CONTEXT.md: Precondition glossary entry as a sibling of Tracer Bullet. - docs/INVENTORY.md + INVENTORY-MANIFEST.json: row for the new references/planner-preconditions.md (regen via gen-inventory-manifest). - tests/precondition-element.test.cjs: failing-first tests covering schema docs, planner emission contract, executor assertion contract, reference-file presence + the three cases, behavioral additive- validator guarantee, and a parity assertion (DEFECT.GENERATIVE-FIX- DIVERGENCE guard). - .changeset/quick-hawks-bark.md: Added fragment. Companion to #1945 (tracer bullets). * chore(#1949): regen agent-size baseline + install-tree goldens Documented baseline regenerations required by the feat(#1949) prose changes (RULESET.AGENT_SIZE_BUDGET + golden-install-parity): - npm run size:baseline — locks in the new gsd-executor.md size (+1050 bytes: the precondition-check step 0 block). gsd-planner.md is net smaller (-142 bytes: compressed two inline summary blocks whose full rules already lived in planner-antipatterns.md to make room for the slim pointer). No hard-cap breach. - npm run gen:golden — pick up the new references/planner-preconditions.md + the two changed agent files across all 18 runtime install trees. Both regens are CI-mandated after intentional agent/reference changes; see CLAUDE.md 'RULESET.AGENT_SIZE_BUDGET' and the comments in tests/golden-install-parity.test.cjs. * fix(#1949): bound checks to read-only (security review) Apply the security-review finding (LOW, isolated /security-review subagent): the executor's 'run the cheapest check' phrasing for a plan-author-controlled prose line was broader than ideal — a hostile plan author could craft a whose 'cheapest check' is side-effecting (curl to an attacker host under the guise of verification, rm -rf before checking, secret emission). The risk is inherited from GSD's existing plan-trust model (, , already direct the executor to run arbitrary shell), so does not materially expand it. But the new prose actively directs execution ('run the check') rather than passively consuming the element, so the bound is worth making explicit. Tightened across all four surfaces that describe the check shape: - agents/gsd-executor.md step 0: 'Verify with read-only checks only — file existence, env var presence (no value output), idempotent GET /health-style pings. Do NOT run commands with side effects (writes, network POSTs, secret emission) as the check; if a side-effecting check seems required, halt and surface via checkpoint instead.' - gsd-core/references/planner-preconditions.md Format section: same bound, plus the halt-and-surface escape hatch. - docs/reference/plan-md.md Preconditions section: mirrored. - CONTEXT.md Precondition glossary entry: mirrored. Regenerated agent-size baseline (executor grew 46186 -> 46440; still under the 49152 cap) and install-tree goldens. * chore(#1949): backfill changeset pr number 2422 Per CONTRIBUTING.md changeset workflow + feature-builder directive Step 8.7: backfill the placeholder pr:0 with the real PR number immediately after gh pr create returns. Avoids the fail_invalid_fragment gate. * fix(#1949): cite [#1949] on allow-test-rule exemption (ADR-456) CI's lint:ci runs lint-allow-test-rule-refs which per ADR-456 requires every // allow-test-rule: exemption on a NEW test file to carry an issue reference (#NNN or URL). My earlier push omitted it. Local 'npm run lint' (eslint) does NOT run this check — only 'npm run lint:ci' does. CLAUDE.md explicitly warns: 'lint:ci ≠ lint — CI runs lint:ci; a local pass is not the gate.' I should have run lint:ci before pushing; correcting now. Pattern matches the companion feature's test file: tests/tracer-bullet.test.cjs:1 // allow-test-rule: source-text-is-the-product [#1945] --- .changeset/quick-hawks-bark.md | 5 + CONTEXT.md | 5 +- agents/gsd-executor.md | 4 + agents/gsd-planner.md | 12 +- docs/INVENTORY-MANIFEST.json | 1 + docs/INVENTORY.md | 1 + docs/reference/plan-md.md | 29 ++- gsd-core/references/planner-preconditions.md | 156 ++++++++++++ tests/agent-size-baseline.json | 4 +- .../golden-install-parity/antigravity.json | 5 +- .../golden-install-parity/augment.json | 5 +- .../golden-install-parity/claude-local.json | 5 +- .../golden-install-parity/claude.json | 5 +- .../fixtures/golden-install-parity/cline.json | 5 +- .../golden-install-parity/codebuddy.json | 5 +- .../fixtures/golden-install-parity/codex.json | 9 +- .../golden-install-parity/copilot.json | 5 +- .../golden-install-parity/cursor.json | 5 +- .../golden-install-parity/hermes.json | 5 +- .../fixtures/golden-install-parity/kilo.json | 5 +- .../fixtures/golden-install-parity/kimi.json | 5 +- .../golden-install-parity/opencode.json | 5 +- tests/fixtures/golden-install-parity/pi.json | 1 + .../fixtures/golden-install-parity/qwen.json | 5 +- .../fixtures/golden-install-parity/trae.json | 5 +- .../golden-install-parity/windsurf.json | 5 +- .../fixtures/golden-install-parity/zcode.json | 5 +- tests/fixtures/install-tree/antigravity.json | 1 + tests/fixtures/install-tree/augment.json | 1 + tests/fixtures/install-tree/claude-local.json | 1 + tests/fixtures/install-tree/claude.json | 1 + tests/fixtures/install-tree/cline.json | 1 + tests/fixtures/install-tree/codebuddy.json | 1 + tests/fixtures/install-tree/codex.json | 1 + tests/fixtures/install-tree/copilot.json | 1 + tests/fixtures/install-tree/cursor.json | 1 + tests/fixtures/install-tree/hermes.json | 1 + tests/fixtures/install-tree/kilo.json | 1 + tests/fixtures/install-tree/kimi.json | 1 + tests/fixtures/install-tree/opencode.json | 1 + tests/fixtures/install-tree/pi.json | 1 + tests/fixtures/install-tree/qwen.json | 1 + tests/fixtures/install-tree/trae.json | 1 + tests/fixtures/install-tree/windsurf.json | 1 + tests/fixtures/install-tree/zcode.json | 1 + tests/precondition-element.test.cjs | 233 ++++++++++++++++++ 46 files changed, 510 insertions(+), 48 deletions(-) create mode 100644 .changeset/quick-hawks-bark.md create mode 100644 gsd-core/references/planner-preconditions.md create mode 100644 tests/precondition-element.test.cjs diff --git a/.changeset/quick-hawks-bark.md b/.changeset/quick-hawks-bark.md new file mode 100644 index 000000000..ec7a8af7f --- /dev/null +++ b/.changeset/quick-hawks-bark.md @@ -0,0 +1,5 @@ +--- +type: Added +pr: 2422 +--- +**`` task element (Design by Contract)** — plans may now declare a runnable/checkable fact a task assumes (env var set, prior-phase artifact present, external-setup done) that plan ordering does not guarantee; the executor asserts it before running the task and halts with a checkpoint on unmet instead of building on a broken assumption. Plans that omit `` behave exactly as today. (#1949) diff --git a/CONTEXT.md b/CONTEXT.md index 7b1dd2500..9933d3381 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -362,7 +362,10 @@ Phase 1 deliverable under `--mvp` on a new project — the Phase-1 whole-applica Single-feature task that moves one user capability from open-to-close (happy path) end-to-end. Contrast with the horizontal layer (all models, then all APIs, then all UI). The default planning unit under tracer-first decomposition (the leading task is a Tracer Bullet); SPIDR Splitting axes (Spike, Paths, Interfaces, Data, Rules) are the canonical decomposition tools when a slice is too large for one phase. ### Tracer Bullet -The default GSD decomposition lead: a **permanent, production-quality, minimal end-to-end slice** that wires one path through every layer a phase touches and becomes part of the skeleton of the final system — written for keeps, not thrown away. Contrast with a **prototype** (throwaway reconnaissance code, deleted once its lesson is learned): a tracer's *functionality* gaps are acceptable but its *architectural* gaps are not; stubs are allowed only where they can later be filled without an architectural change. GSD ships tracers, never prototypes — which is why `gsd-planner` LEADS every plan with a `type="tracer"` task (default; `--no-tracer` / `TRACER_MODE=false` opts back into horizontal layers) and `gsd-executor` runs an early integration feedback gate on the tracer's `` before expansion tasks (autonomous: halt-on-fail; interactive: `checkpoint:human-verify`). Origin: *The Pragmatic Programmer* "Tracer Bullets" (#1945); the Walking Skeleton is the Phase-1 whole-application special case. See Vertical Slice, MVP Mode, Walking Skeleton. +The default GSD decomposition lead: a **permanent, production-quality, minimal end-to-end slice** that wires one path through every layer a phase touches and becomes part of the skeleton of the final system — written for keeps, not thrown away. Contrast with a **prototype** (throwaway reconnaissance code, deleted once its lesson is learned): a tracer's *functionality* gaps are acceptable but its *architectural* gaps are not; stubs are allowed only where they can later be filled without an architectural change. GSD ships tracers, never prototypes — which is why `gsd-planner` LEADS every plan with a `type="tracer"` task (default; `--no-tracer` / `TRACER_MODE=false` opts back into horizontal layers) and `gsd-executor` runs an early integration feedback gate on the tracer's `` before expansion tasks (autonomous: halt-on-fail; interactive: `checkpoint:human-verify`). Origin: *The Pragmatic Programmer* "Tracer Bullets" (#1945); the Walking Skeleton is the Phase-1 whole-application special case. See Vertical Slice, MVP Mode, Walking Skeleton, Precondition. + +### Precondition +The front-of-task side of the GSD plan contract (issue #1949, *The Pragmatic Programmer* Topic 23 — Design by Contract). An optional `` element on `` stating, in a single line of runnable/checkable prose, what must already be true for the task to begin safely — e.g. "`OPENAI_API_KEY` is set", "`dist/schema.json` from Phase 02 exists", "server responds to GET /health". `gsd-executor` evaluates it before any other task work, using **read-only checks only** (file existence, env var presence with no value output, idempotent `GET /health`-style pings — no writes, no network POSTs, no secret emission; if a side-effecting check seems required, the executor halts and surfaces a checkpoint rather than running it): met-or-absent is a no-op (back-compat for every existing plan); unmet returns a `checkpoint:human-verify` with no partial commit, and is NEVER auto-approved under `AUTO_CFG=true` (a missing prerequisite is a fact the executor cannot establish on its own, not a verification step). `gsd-planner` emits `` in exactly three cases — `user_setup` consumption, prior-phase artifact dependency, or env-var/runtime-config dependency — when the assumption is not already guaranteed by `depends_on` ordering. Closes the contract triad whose other two sides are postconditions (``/``/``) and invariants (`must_haves.truths`). The structural validator (`cmdVerifyPlanStructure`) does not reject unknown optional tags, so adding `` passes plan-structure validation unchanged. Canonical schema reference: `docs/reference/plan-md.md` → Preconditions; emission rules + anti-patterns: `gsd-core/references/planner-preconditions.md`. The architectural-end companion is the Tracer Bullet (#1945); together they close both ends of the "outrunning your headlights" failure mode. See Tracer Bullet. ### Behavior-Adding Task Predicate over a PLAN.md task: `tdd="true"` frontmatter AND `` block names a user-visible outcome AND `` includes at least one non-`*.md` / non-`*.json` / non-`*.test.*` source file. Pure doc/config/test-only tasks are exempt. The MVP+TDD Gate (in `references/execute-mvp-tdd.md`) only halts execution on this predicate; the gsd-executor agent applies all three checks at runtime. Currently a prose-only specification — no shared utility. diff --git a/agents/gsd-executor.md b/agents/gsd-executor.md index 3e2db5fe2..78cac9406 100644 --- a/agents/gsd-executor.md +++ b/agents/gsd-executor.md @@ -144,6 +144,10 @@ At execution decision points, apply structured reasoning: For each task: +0. **Precondition check (before any other task work):** If the task carries a `` element, evaluate that single prose line first — it names a runnable/checkable fact the task assumes (env var set, prior-phase artifact present, server responding to `/health`, `user_setup` step done). Verify with **read-only checks only** — file existence, env var presence (no value output), idempotent `GET /health`-style pings. Do NOT run commands with side effects (writes, network POSTs, secret emission) as the check; if a side-effecting check seems required, halt and surface via checkpoint instead. + - **Met OR absent:** continue with no visible change to execution flow. The precondition is a no-op for the rest of the task loop. + - **Unmet:** STOP — return a `checkpoint:human-verify` (use `checkpoint_return_format`) with `**Blocked by:** Precondition not met: `. Do NOT partial-commit the task. Unmet preconditions are NEVER auto-approved, even under `AUTO_CFG=true` — a missing prerequisite is not a verification step a human can rubber-stamp; it is a fact the executor cannot establish on its own. The human either satisfies the precondition (sets the env var, completes the `user_setup` step, regenerates the artifact) or reruns `/gsd:plan-phase` to restructure. + 1. **If `type="auto"`:** - Check for `tdd="true"` → follow TDD execution flow - Execute task, apply deviation rules as needed diff --git a/agents/gsd-planner.md b/agents/gsd-planner.md index 50881ec67..e5b2a51ad 100644 --- a/agents/gsd-planner.md +++ b/agents/gsd-planner.md @@ -193,23 +193,19 @@ Every task has four required fields: **Grep gate hygiene:** `grep -c` counts comments, so header prose can be self-invalidating. Use `grep -v '^#' | grep -c token`. Bare `== 0` gates on unfiltered files are forbidden. -**Comment-text discipline (HARD GATE, #429):** A literal an acceptance criterion negative-greps for (`grep -c 'LIT' file == 0`) must NOT appear verbatim in any `` body — JSDoc samples, head-comment references, or "what NOT to do" snippets echo into the written file and trip the executor's commit-time gate. `validate_plan` (`verify.plan-structure`) fails plan creation on violation. Rephrase the literal by concept, or — when it must legitimately appear — add an allowlist marker on its own line: - -`` - -Full rules + worked examples: @gsd-core/references/planner-antipatterns.md ("Comment-Text Discipline"). +**Comment-text discipline (HARD GATE, #429):** A literal an acceptance criterion negative-greps for must NOT appear verbatim in any `` body. Full rules + `` allowlist + worked examples: @gsd-core/references/planner-antipatterns.md ("Comment-Text Discipline"). -**Region-scoped negative gates (WARN, #968):** Region-scope a file-wide negative grep when a sibling task needs that construct elsewhere in the same file; `validate_plan` WARNS. See: @gsd-core/references/planner-antipatterns.md ("Region-Scoped Negative Gates"). - -**Verify-gate hygiene (#1478/#1479):** See @gsd-core/references/planner-antipatterns.md. +**Region-scoped negative gates (WARN, #968)** and **Verify-gate hygiene (#1478/#1479):** @gsd-core/references/planner-antipatterns.md. **:** Acceptance criteria - measurable state of completion. - Good: "Valid credentials return 200 + JWT cookie, invalid credentials return 401" - Bad: "Authentication is complete" +**** (optional, one prose line): a runnable/checkable fact the task assumes that plan ordering does not guarantee — external setup (`user_setup`), a prior-phase artifact, or an env var. The executor asserts it before running the task and halts on unmet. Emission rules + the contract triad (precondition ↔ ``/`` ↔ `must_haves.truths`): @~/.claude/gsd-core/references/planner-preconditions.md. + See @~/.claude/gsd-core/references/planner-guidance.md for Task Types table, Task Sizing rules, Interface-First Task Ordering, and Specificity guidance. ## TDD Detection diff --git a/docs/INVENTORY-MANIFEST.json b/docs/INVENTORY-MANIFEST.json index 31a3c753b..d445161cd 100644 --- a/docs/INVENTORY-MANIFEST.json +++ b/docs/INVENTORY-MANIFEST.json @@ -254,6 +254,7 @@ "planner-interface-context.md", "planner-load-graph-context.md", "planner-mvp-mode.md", + "planner-preconditions.md", "planner-reviews.md", "planner-revision.md", "planner-source-audit.md", diff --git a/docs/INVENTORY.md b/docs/INVENTORY.md index 8de2825bc..d6d2990cb 100644 --- a/docs/INVENTORY.md +++ b/docs/INVENTORY.md @@ -385,6 +385,7 @@ The `gsd-planner` agent is decomposed into a core agent plus reference modules t | `planner-revision.md` | Plan revision patterns for iterative refinement. | | `planner-source-audit.md` | Planner source-audit and authority-limit rules. | | `planner-mvp-mode.md` | Vertical-slice planning rules for MVP mode. | +| `planner-preconditions.md` | Emission rules for the optional `` task element (issue #1949, Design by Contract): when to emit, the three cases (user_setup / prior-phase artifact / env-var), format, anti-patterns, and the contract triad mapping. | | `planner-human-verify-mode.md` | Rules for `workflow.human_verify_mode = end-of-phase`: suppress `checkpoint:human-verify` task emission and route deferred items via ``. | | `planner-graphify-auto-update.md` | How `load_graph_context` surfaces `.last-build-status.json` auto-update state (running / failed / stale head) alongside the existing staleness annotation. Opt-in via `graphify.auto_update` (#3347). | | `planner-interface-context.md` | Interface context rules for executors — how to extract key interfaces/types/exports from existing code and document new interfaces that downstream plans will consume. | diff --git a/docs/reference/plan-md.md b/docs/reference/plan-md.md index 079e3a6f4..10b707d2f 100644 --- a/docs/reference/plan-md.md +++ b/docs/reference/plan-md.md @@ -160,7 +160,34 @@ References source files the executor needs to read. Includes project-level plann ### `` -Contains one or more `` elements. Every task element must carry ``, ``, ``, ``, ``, ``, and `` for `type="auto"` and `type="tracer"` tasks. +Contains one or more `` elements. Every task element must carry ``, ``, ``, ``, ``, ``, and `` for `type="auto"` and `type="tracer"` tasks. An optional `` element (see [Preconditions](#preconditions)) may sit between `` and ``. + +--- + +## Preconditions + +`` is an **optional** element on `` (issue #1949, *The Pragmatic Programmer* Topic 23 — Design by Contract). It states, in a single line of runnable/checkable prose, what must already be true for the task to begin safely. It closes the front-of-task side of the contract triad — preconditions (before) ↔ postconditions (``/``/``, after) ↔ invariants (`must_haves.truths`, across the whole plan). + +```xml + + Add /reveal endpoint handler + server bootstraps and responds to GET /health (from the tracer slice) + server/reveal.ts + … + curl /reveal?path=… opens the OS file manager + Endpoint committed and manually verified + +``` + +**Optional and back-compat:** a plan that omits `` on every task behaves exactly as today — the executor skips the check with no visible change. Adding `` to a task tells the executor to assert it before any other task work (read-only checks only: file existence, env var presence, idempotent health pings; no side-effecting checks — halt and surface a checkpoint if one seems required) and halt (returning a `checkpoint:human-verify`, no partial commit) on an unmet precondition. Plans that include `` pass `verify plan-structure` unchanged — the structural validator checks for the presence of required tags and does not reject unknown optional tags. + +**Emission cases** (planner-side): emit `` only when a task relies on state the plan's own `depends_on` ordering does not already guarantee. Three cases cover every legitimate use: + +1. **External service setup** (`user_setup` frontmatter) — the consuming task ties a specific setup step to itself so the executor halts if the setup was skipped. +2. **Prior-phase artifact dependency** — a generated schema, a migration's dist output, a contract file from an earlier phase. Cross-phase `depends_on` does not cross phase boundaries, so `` is the explicit pointer. +3. **Environment variable / runtime configuration** — a tool, API, or script the task invokes requires an env var or runtime config that exists *now*, not at plan time. + +Full emission rules, anti-patterns ("the system is ready" is not checkable; do not use `` for intra-plan sequencing — that is what `depends_on` is for), and the contract triad mapping: see `gsd-core/references/planner-preconditions.md`. --- diff --git a/gsd-core/references/planner-preconditions.md b/gsd-core/references/planner-preconditions.md new file mode 100644 index 000000000..92cbafd99 --- /dev/null +++ b/gsd-core/references/planner-preconditions.md @@ -0,0 +1,156 @@ +# Planner Preconditions — `` Element + +> Progressive-disclosure reference for `agents/gsd-planner.md`. The planner agent +> reads this file when it needs the full emission rules for the `` +> task element (issue #1949, *The Pragmatic Programmer* Topic 23 — Design by +> Contract). The slim pointer in `agents/gsd-planner.md` → `` +> routes here; the canonical schema row lives in `docs/reference/plan-md.md`. + +## The contract triad + +Every task in a PLAN.md participates in a three-sided contract: + +| Contract side | GSD element | When it binds | +|---|---|---| +| **Precondition** | `` (optional element on ``) | Before the task begins. What must already be true for the task to run safely. | +| **Postcondition** | `` + `` + `` | After the task ends. What the task guarantees on return. | +| **Invariant** | `must_haves.truths` (plan frontmatter) | Across the whole plan/phase. What always holds. | + +GSD already models postconditions and invariants well. `` closes +the missing side: it states, in runnable/checkable terms, what must be true +*before* a task begins — so an autonomous executor stops the instant an +assumption is false, instead of building ten atomic commits on top of a +migration that never ran. + +This is the front-of-task companion to the tracer-bullet proposal (#1945): +tracers prove the *architecture* end-to-end before expansion; preconditions prove +each expansion task's *assumptions* before it runs. Together they close both ends +of the "outrunning your headlights" failure mode. + +## When to emit `` + +Emit `` ONLY when a task relies on state the plan's own `depends_on` +ordering does not already guarantee. Three cases cover every legitimate use; if +the task's prerequisite is intra-plan sequencing, use `depends_on`, NOT +``. + +### Case 1 — External service setup (`user_setup`) + +The task depends on an external service the developer must set up (account +creation, secret retrieval, dashboard configuration, billing activation). The +`user_setup` frontmatter field already enumerates these steps; `` +on the consuming task ties a specific setup step to a specific task so the +executor halts if the setup was skipped. + +```xml + + Send welcome email via SendGrid + SENDGRID_API_KEY is set (user_setup step 1 complete) + src/email/welcome.ts + ... + ... + Welcome email dispatched for a test user + +``` + +### Case 2 — Prior-phase artifact dependency + +The task consumes an artifact a prior phase promised (a generated schema, a +migration's dist output, a contract file). Cross-phase `depends_on` does not +cross phase boundaries, so a `` is the explicit pointer. + +```xml + + Generate TypeScript client from schema + dist/schema.json from Phase 02 exists and is non-empty + src/client/generated.ts + ... + ... + Client generated and compiles + +``` + +### Case 3 — Environment variable / runtime configuration + +The task shells out to a tool, hits an API, or runs a script that requires an +environment variable or runtime config that exists *now* (not at plan time). + +```xml + + Add /reveal endpoint handler + server bootstraps and responds to GET /health (from the tracer slice) + server/reveal.ts + ... + curl /reveal?path=... opens the OS file manager + Endpoint committed and manually verified + +``` + +## Format + +`` is a single line of prose inside the `` element, placed right after `` and before ``. It is **prose, not a structured block** — concrete enough that the executor agent can run a read-only check (file existence, env var presence, idempotent `GET /health`-style ping), prose enough not to require a parser extension. The executor MUST verify with read-only checks only: no writes, no network POSTs, no secret emission. If a side-effecting check seems required, the executor halts and surfaces a checkpoint rather than running it. + +```xml + + ... + ... + ... + ... + ... + ... + +``` + +## What NOT to put in a `` + +- **Vague readiness checks.** "The system is ready" is not checkable. Name the + concrete signal: a `curl` response, a file path, an env var name. +- **Intra-plan ordering.** "Task 1 has completed" — that is what `depends_on` + is for. Reserve `` for state the plan's wave/dependency graph + cannot express. +- **Implementation choices.** "We have chosen library X" — that belongs in the + `` body or a `## Decisions` row, not a runtime fact. +- **Things the task itself creates.** A precondition names a fact the task + *assumes*; if the task produces it, it is a postcondition (``). + +## Executor behavior (assertion contract) + +The executor agent reads `` before any other task work: + +| State | Executor behavior | +|---|---| +| **Absent** | No visible change — execute the task exactly as today. Back-compat for every existing plan. | +| **Met** | No visible change — proceed with the task. The precondition is logged in the SUMMARY only if it was non-trivial to verify. | +| **Unmet** | STOP — return a `checkpoint:human-verify` (use `checkpoint_return_format`) with `**Blocked by:** Precondition not met: `. Do NOT partial-commit the task. Unmet preconditions are NEVER auto-approved — a missing prerequisite is not a verification step a human can rubber-stamp, it is a fact the executor cannot establish on its own. | + +## Plan-structure validation + +`cmdVerifyPlanStructure` checks for the presence of required tags (``, +``, etc.) and warns on missing recommended tags (``, ``, +``). It does **not** reject unknown optional tags, so adding +`` to a plan passes validation unchanged. A future ADR may add +structured validation if drift emerges; v1 ships prose-only to keep the surface +minimal (Hyrum's Law: the smaller the observable surface, the less the system +depends on by accident). + +## Out of scope + +The following are explicitly NOT part of v1: + +- **Structured precondition DSL** (e.g. ``). + Prose-first keeps complexity flat; structured validation can land in a later + PR if prose proves insufficient. +- **Automatic precondition emission for every task.** The three cases above are + a hard ceiling (Zawinski's Law guard). Most tasks do not need a precondition. +- **Cross-task preconditions.** A precondition binds one task to one fact. Use + `depends_on` or a parent plan's `must_haves` for multi-task contracts. + +## See also + +- *The Pragmatic Programmer*, Topic 23 — "Design by Contract" (Hunt & Thomas). +- `docs/reference/plan-md.md` — canonical PLAN.md schema reference (where + `` appears in the task-element table). +- Tracer-bullet proposal (#1945) — the architectural-end companion to this + front-of-task contract. +- `agents/gsd-executor.md` → `` → precondition check step — the + assertion surface that consumes what this reference defines. diff --git a/tests/agent-size-baseline.json b/tests/agent-size-baseline.json index 11212ff5e..b0b2e09e7 100644 --- a/tests/agent-size-baseline.json +++ b/tests/agent-size-baseline.json @@ -14,7 +14,7 @@ "gsd-domain-researcher.md": 7032, "gsd-eval-auditor.md": 12496, "gsd-eval-planner.md": 7008, - "gsd-executor.md": 45338, + "gsd-executor.md": 46644, "gsd-framework-selector.md": 6778, "gsd-integration-checker.md": 15238, "gsd-intel-updater.md": 18166, @@ -23,7 +23,7 @@ "gsd-pattern-mapper.md": 12487, "gsd-phase-researcher.md": 40866, "gsd-plan-checker.md": 44780, - "gsd-planner.md": 49314, + "gsd-planner.md": 49172, "gsd-project-researcher.md": 22242, "gsd-research-synthesizer.md": 13847, "gsd-roadmapper.md": 22273, diff --git a/tests/fixtures/golden-install-parity/antigravity.json b/tests/fixtures/golden-install-parity/antigravity.json index baeb46666..8097d04ea 100644 --- a/tests/fixtures/golden-install-parity/antigravity.json +++ b/tests/fixtures/golden-install-parity/antigravity.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "1db46cac3f4d9889", "agents/gsd-eval-auditor.md": "1b8391f1aafb067f", "agents/gsd-eval-planner.md": "3d10fd11147f6857", - "agents/gsd-executor.md": "5dc97b2515b36731", + "agents/gsd-executor.md": "152955064cf4c9d2", "agents/gsd-framework-selector.md": "daa62c79619c76bf", "agents/gsd-integration-checker.md": "0643cd2d779b131c", "agents/gsd-intel-updater.md": "26c1f1e028c6346a", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "e62ee90d39084802", "agents/gsd-phase-researcher.md": "cff1196c8e8bb4fa", "agents/gsd-plan-checker.md": "dd1e7cdc837d8f3e", - "agents/gsd-planner.md": "c5de6bb9b277e4d4", + "agents/gsd-planner.md": "6a442501f9d4caa8", "agents/gsd-project-researcher.md": "85de7f562872ee9b", "agents/gsd-research-synthesizer.md": "18a2e1b30ff7ae3a", "agents/gsd-roadmapper.md": "7a8465ac6d4dd29e", @@ -115,6 +115,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "90cb2ecd1f3eb4d8", "gsd-core/references/planner-mvp-mode.md": "cdac9dde7cd8fa84", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/augment.json b/tests/fixtures/golden-install-parity/augment.json index eaab16494..364625d6f 100644 --- a/tests/fixtures/golden-install-parity/augment.json +++ b/tests/fixtures/golden-install-parity/augment.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "671c9ea949889c4a", "agents/gsd-eval-auditor.md": "fcaec7b00f94c435", "agents/gsd-eval-planner.md": "a4a5b4b3f7828ba3", - "agents/gsd-executor.md": "2df526331a77b2aa", + "agents/gsd-executor.md": "47c648f6622e939f", "agents/gsd-framework-selector.md": "4b77eebbe9288d80", "agents/gsd-integration-checker.md": "fa53e2d78be1de74", "agents/gsd-intel-updater.md": "fa40e685d7441ace", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "43c6021cf7caabfa", "agents/gsd-phase-researcher.md": "f1f6fd6a3e67c7a8", "agents/gsd-plan-checker.md": "bf1a4e636f2390de", - "agents/gsd-planner.md": "4614c9f6250d08d4", + "agents/gsd-planner.md": "55cc953c6a52ae05", "agents/gsd-project-researcher.md": "4531b7cc8f5e5f7d", "agents/gsd-research-synthesizer.md": "4a4f68e6c75b133a", "agents/gsd-roadmapper.md": "bb2f57695dbab32c", @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "ca7a7af3f35ae61b", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "dda0193a0fbd4947", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/claude-local.json b/tests/fixtures/golden-install-parity/claude-local.json index db988733b..311b0e65c 100644 --- a/tests/fixtures/golden-install-parity/claude-local.json +++ b/tests/fixtures/golden-install-parity/claude-local.json @@ -15,7 +15,7 @@ "agents/gsd-domain-researcher.md": "f1e03df842ddfb95", "agents/gsd-eval-auditor.md": "d0f45fff7370bb0b", "agents/gsd-eval-planner.md": "9cc049b82897daa4", - "agents/gsd-executor.md": "e96f3cbde4428497", + "agents/gsd-executor.md": "3c8d4fd1c29542bb", "agents/gsd-framework-selector.md": "85005d716f9d98f7", "agents/gsd-integration-checker.md": "17a8ee731986564d", "agents/gsd-intel-updater.md": "4953a465db9dadc1", @@ -24,7 +24,7 @@ "agents/gsd-pattern-mapper.md": "b45b5e106775bec1", "agents/gsd-phase-researcher.md": "4772d9eada32e8bd", "agents/gsd-plan-checker.md": "75851b147f35354a", - "agents/gsd-planner.md": "a5cdb261a6ccbb96", + "agents/gsd-planner.md": "4636f48b1b7ca1f6", "agents/gsd-project-researcher.md": "d7f355894519f9fe", "agents/gsd-research-synthesizer.md": "1c738df9932d325a", "agents/gsd-roadmapper.md": "453e9471ad27c7ea", @@ -185,6 +185,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "add55e135dd968da", "gsd-core/references/planner-mvp-mode.md": "98bcd2020c30cbd2", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/claude.json b/tests/fixtures/golden-install-parity/claude.json index af6265f3f..5f7be45b6 100644 --- a/tests/fixtures/golden-install-parity/claude.json +++ b/tests/fixtures/golden-install-parity/claude.json @@ -15,7 +15,7 @@ "agents/gsd-domain-researcher.md": "5f7d366251b957fe", "agents/gsd-eval-auditor.md": "fea2759beff0a642", "agents/gsd-eval-planner.md": "112f6730f23854e3", - "agents/gsd-executor.md": "e44ea5156ca2a42d", + "agents/gsd-executor.md": "e63187a0bbff74eb", "agents/gsd-framework-selector.md": "c350ee693cb1aa4e", "agents/gsd-integration-checker.md": "c8b4e65dee89c8ea", "agents/gsd-intel-updater.md": "5b41e05f90ce89d9", @@ -24,7 +24,7 @@ "agents/gsd-pattern-mapper.md": "b45b5e106775bec1", "agents/gsd-phase-researcher.md": "85217c69c1ed2ac6", "agents/gsd-plan-checker.md": "c70134c61b969589", - "agents/gsd-planner.md": "c07a226ddd579839", + "agents/gsd-planner.md": "3098091aa1f0756d", "agents/gsd-project-researcher.md": "f468e96f8339d1e0", "agents/gsd-research-synthesizer.md": "7be02e47f4fd901b", "agents/gsd-roadmapper.md": "8a7f1f1256a6aed5", @@ -114,6 +114,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "ca7a7af3f35ae61b", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/cline.json b/tests/fixtures/golden-install-parity/cline.json index 351f1e12b..84ac13c4e 100644 --- a/tests/fixtures/golden-install-parity/cline.json +++ b/tests/fixtures/golden-install-parity/cline.json @@ -19,7 +19,7 @@ "agents/gsd-domain-researcher.md": "0fecdaea86466a56", "agents/gsd-eval-auditor.md": "36c44303085df2f8", "agents/gsd-eval-planner.md": "3ddea88a69b4da3f", - "agents/gsd-executor.md": "9b51734f64049fda", + "agents/gsd-executor.md": "343f7d59b160d74a", "agents/gsd-framework-selector.md": "564669d479433f15", "agents/gsd-integration-checker.md": "1bbbdd3d420b994e", "agents/gsd-intel-updater.md": "42c40fffbc720d0b", @@ -28,7 +28,7 @@ "agents/gsd-pattern-mapper.md": "b526065fd2efa19c", "agents/gsd-phase-researcher.md": "c507db2ba66038f4", "agents/gsd-plan-checker.md": "a609245dbdc4ef2b", - "agents/gsd-planner.md": "2fa5c5d4529ef651", + "agents/gsd-planner.md": "c2ab476257cd07cf", "agents/gsd-project-researcher.md": "049f816c6caa4316", "agents/gsd-research-synthesizer.md": "2f7dcbff50371d4c", "agents/gsd-roadmapper.md": "bbb23d3097911516", @@ -118,6 +118,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "e469016f2d51b5bc", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "dda0193a0fbd4947", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/codebuddy.json b/tests/fixtures/golden-install-parity/codebuddy.json index 301779bca..380fcc5cd 100644 --- a/tests/fixtures/golden-install-parity/codebuddy.json +++ b/tests/fixtures/golden-install-parity/codebuddy.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "1c1a800108a2b225", "agents/gsd-eval-auditor.md": "99012004b14ea602", "agents/gsd-eval-planner.md": "4ebdd7fe9cbb0cfe", - "agents/gsd-executor.md": "4f4bbb77be53a135", + "agents/gsd-executor.md": "44149e405a126f90", "agents/gsd-framework-selector.md": "7726fccc86bfeb50", "agents/gsd-integration-checker.md": "2d8339790bbb2dc3", "agents/gsd-intel-updater.md": "c51339956197cbd3", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "92cfa2e6c2a06bf3", "agents/gsd-phase-researcher.md": "6338474da1a5d65e", "agents/gsd-plan-checker.md": "e704c083b02e8c35", - "agents/gsd-planner.md": "1ade235391742f7e", + "agents/gsd-planner.md": "8e3e314f962711cd", "agents/gsd-project-researcher.md": "e43c59f7f1f2f37a", "agents/gsd-research-synthesizer.md": "87955470c3c129b2", "agents/gsd-roadmapper.md": "20b69eff61a7a9fa", @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "ca7a7af3f35ae61b", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "dda0193a0fbd4947", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/codex.json b/tests/fixtures/golden-install-parity/codex.json index a590c9f8f..e4be6d98f 100644 --- a/tests/fixtures/golden-install-parity/codex.json +++ b/tests/fixtures/golden-install-parity/codex.json @@ -102,8 +102,8 @@ "agents/gsd-eval-auditor.toml": "9b81d61b3c5f722d", "agents/gsd-eval-planner.md": "73f2ad2ff2797a51", "agents/gsd-eval-planner.toml": "09468ad1a34ac468", - "agents/gsd-executor.md": "895482e838b13815", - "agents/gsd-executor.toml": "a95f6ad24154e646", + "agents/gsd-executor.md": "ed8080096522f7ec", + "agents/gsd-executor.toml": "126d79d90e2fdf4f", "agents/gsd-framework-selector.md": "ebae32430887d2e0", "agents/gsd-framework-selector.toml": "637e4e021b7ec380", "agents/gsd-integration-checker.md": "9cc875676cf7d741", @@ -120,8 +120,8 @@ "agents/gsd-phase-researcher.toml": "44a3d510cd0ce3bd", "agents/gsd-plan-checker.md": "e7f02c10ea788aee", "agents/gsd-plan-checker.toml": "6f8ceb421d0ad721", - "agents/gsd-planner.md": "7d48d3a81760af05", - "agents/gsd-planner.toml": "2527d19b0c47ec66", + "agents/gsd-planner.md": "cb3ff2ef2c58617c", + "agents/gsd-planner.toml": "ac51638704036f71", "agents/gsd-project-researcher.md": "959f2e57c3d69ed8", "agents/gsd-project-researcher.toml": "f395e8e8c4baf1ed", "agents/gsd-research-synthesizer.md": "497f85adf53259ef", @@ -221,6 +221,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "ca7a7af3f35ae61b", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "7889bfa28e82156b", "gsd-core/references/planner-revision.md": "2ebf1a714d1ec4bf", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/copilot.json b/tests/fixtures/golden-install-parity/copilot.json index 7f22b3a69..d0e7cc629 100644 --- a/tests/fixtures/golden-install-parity/copilot.json +++ b/tests/fixtures/golden-install-parity/copilot.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.agent.md": "d603239b3e9fe428", "agents/gsd-eval-auditor.agent.md": "3c03009564de55c8", "agents/gsd-eval-planner.agent.md": "14751876fc2b5f16", - "agents/gsd-executor.agent.md": "761523a925bd2649", + "agents/gsd-executor.agent.md": "e75e46a35b7b260a", "agents/gsd-framework-selector.agent.md": "cafeec0b3489be45", "agents/gsd-integration-checker.agent.md": "30439b804927acc7", "agents/gsd-intel-updater.agent.md": "238c1a886f35a25c", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.agent.md": "b1f488b0fa6a2395", "agents/gsd-phase-researcher.agent.md": "03cfb510a766fe93", "agents/gsd-plan-checker.agent.md": "c50a5b008ddcbfad", - "agents/gsd-planner.agent.md": "2664dc34defa7580", + "agents/gsd-planner.agent.md": "8f5f400efea5e446", "agents/gsd-project-researcher.agent.md": "d73bdbe986ffa8a6", "agents/gsd-research-synthesizer.agent.md": "f03eed4aa89e47c5", "agents/gsd-roadmapper.agent.md": "322048cf8ddcb4e5", @@ -116,6 +116,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "641b6c1ce4dd0c8c", "gsd-core/references/planner-mvp-mode.md": "355d8a9ff2b2b67e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/cursor.json b/tests/fixtures/golden-install-parity/cursor.json index 730759255..cced95471 100644 --- a/tests/fixtures/golden-install-parity/cursor.json +++ b/tests/fixtures/golden-install-parity/cursor.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "56395dbdabf076f6", "agents/gsd-eval-auditor.md": "ad2840fd5cd76172", "agents/gsd-eval-planner.md": "2049dac060d00eda", - "agents/gsd-executor.md": "68796b76140841c2", + "agents/gsd-executor.md": "e3d78836e115b18c", "agents/gsd-framework-selector.md": "4b77eebbe9288d80", "agents/gsd-integration-checker.md": "5da30584d06b878c", "agents/gsd-intel-updater.md": "b8971c5d96e63b38", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "1229c215677f740d", "agents/gsd-phase-researcher.md": "982d59921bed463d", "agents/gsd-plan-checker.md": "ba51999876d40cf2", - "agents/gsd-planner.md": "1feec75fe52b56bd", + "agents/gsd-planner.md": "c788d7fb84cf5433", "agents/gsd-project-researcher.md": "beeac940d3a10e76", "agents/gsd-research-synthesizer.md": "6315f016d55176f4", "agents/gsd-roadmapper.md": "d28e7d4bac46dde2", @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "ca7a7af3f35ae61b", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/hermes.json b/tests/fixtures/golden-install-parity/hermes.json index c9eb14893..985d27178 100644 --- a/tests/fixtures/golden-install-parity/hermes.json +++ b/tests/fixtures/golden-install-parity/hermes.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "412cdbb05ba252ea", "agents/gsd-eval-auditor.md": "4ffb265063c318e5", "agents/gsd-eval-planner.md": "03448fc9c5774b56", - "agents/gsd-executor.md": "c1f807f853dc53d7", + "agents/gsd-executor.md": "b70c976372c77dc1", "agents/gsd-framework-selector.md": "ea9981d65d6b3429", "agents/gsd-integration-checker.md": "35b4f2969d279871", "agents/gsd-intel-updater.md": "5fe5edfae2719cb8", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "cea092600aeb3978", "agents/gsd-phase-researcher.md": "2bd0402f33d757ca", "agents/gsd-plan-checker.md": "4b4e2b475bf5b5c3", - "agents/gsd-planner.md": "a48726410b038084", + "agents/gsd-planner.md": "d5fa8236f975aacd", "agents/gsd-project-researcher.md": "425a7df7f37a5c06", "agents/gsd-research-synthesizer.md": "9d31c87fc2c87ffa", "agents/gsd-roadmapper.md": "64dce5d5f9fa5654", @@ -115,6 +115,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "8f598e08696843c0", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/kilo.json b/tests/fixtures/golden-install-parity/kilo.json index 6c47ac40b..9583bb9e3 100644 --- a/tests/fixtures/golden-install-parity/kilo.json +++ b/tests/fixtures/golden-install-parity/kilo.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "a3874d80bcbc7380", "agents/gsd-eval-auditor.md": "630d4cd3bd6ea195", "agents/gsd-eval-planner.md": "3db12cde12aeb2c1", - "agents/gsd-executor.md": "c53d111b0c795f7c", + "agents/gsd-executor.md": "73278ea652cac62f", "agents/gsd-framework-selector.md": "ad5f2c6b9bec6270", "agents/gsd-integration-checker.md": "c503e2f4a3d8ec05", "agents/gsd-intel-updater.md": "231393da62a45b2e", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "6a5408fd11d70391", "agents/gsd-phase-researcher.md": "94818f28c498bb26", "agents/gsd-plan-checker.md": "56164206242c8caf", - "agents/gsd-planner.md": "1fbe1f6e9c3b74f0", + "agents/gsd-planner.md": "13c4b6db72b6bbb3", "agents/gsd-project-researcher.md": "60573a38d3dfd9fe", "agents/gsd-research-synthesizer.md": "1f7cd286c5783c86", "agents/gsd-roadmapper.md": "277e0a3252553ab7", @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "ca7a7af3f35ae61b", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/kimi.json b/tests/fixtures/golden-install-parity/kimi.json index 3e490e8ca..09e5b64f5 100644 --- a/tests/fixtures/golden-install-parity/kimi.json +++ b/tests/fixtures/golden-install-parity/kimi.json @@ -61,7 +61,7 @@ "agents/subagents/gsd-eval-auditor.yaml": "e3d868bd5fefe938", "agents/subagents/gsd-eval-planner.md": "70f8c5727bfb9876", "agents/subagents/gsd-eval-planner.yaml": "df8499f7af297ec2", - "agents/subagents/gsd-executor.md": "948d122c6607e343", + "agents/subagents/gsd-executor.md": "20cf0b2aa886d35c", "agents/subagents/gsd-executor.yaml": "e29422986636fd64", "agents/subagents/gsd-framework-selector.md": "a15b7aa1e0576e16", "agents/subagents/gsd-framework-selector.yaml": "fb52c31cde27b0e3", @@ -79,7 +79,7 @@ "agents/subagents/gsd-phase-researcher.yaml": "7633c8e82617e7cc", "agents/subagents/gsd-plan-checker.md": "bd302afc01ed40f0", "agents/subagents/gsd-plan-checker.yaml": "8295181071121db8", - "agents/subagents/gsd-planner.md": "aaaac708b1cf2939", + "agents/subagents/gsd-planner.md": "d29376ff9f57cc60", "agents/subagents/gsd-planner.yaml": "2e83ee194bcd7fbd", "agents/subagents/gsd-project-researcher.md": "39bc2ec5a8b18283", "agents/subagents/gsd-project-researcher.yaml": "ce12586b0347e2dc", @@ -179,6 +179,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "ca7a7af3f35ae61b", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "dda0193a0fbd4947", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/opencode.json b/tests/fixtures/golden-install-parity/opencode.json index d3e63a042..996dd209d 100644 --- a/tests/fixtures/golden-install-parity/opencode.json +++ b/tests/fixtures/golden-install-parity/opencode.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "71250e759ca9e723", "agents/gsd-eval-auditor.md": "c88890105f32ace6", "agents/gsd-eval-planner.md": "60bddb70a937f796", - "agents/gsd-executor.md": "4f180ee85214abe8", + "agents/gsd-executor.md": "84c0a7dc19ddb6c5", "agents/gsd-framework-selector.md": "1c0a10355e787675", "agents/gsd-integration-checker.md": "a9de5928e5a5c649", "agents/gsd-intel-updater.md": "493e07482fa6198a", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "7c6d1d9817a9c1e7", "agents/gsd-phase-researcher.md": "9874110700b41f48", "agents/gsd-plan-checker.md": "28ca3dc43669894f", - "agents/gsd-planner.md": "4e568338c7ee6b80", + "agents/gsd-planner.md": "87d1aa910eb02ad5", "agents/gsd-project-researcher.md": "dae210ae0b3c6e2b", "agents/gsd-research-synthesizer.md": "e02c6ad5d1b74171", "agents/gsd-roadmapper.md": "1658a40b20d8b575", @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "97f6e67b56c072c1", "gsd-core/references/planner-mvp-mode.md": "35d30284ea9110c0", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/pi.json b/tests/fixtures/golden-install-parity/pi.json index b87f500f2..30bf878f2 100644 --- a/tests/fixtures/golden-install-parity/pi.json +++ b/tests/fixtures/golden-install-parity/pi.json @@ -82,6 +82,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "ca7a7af3f35ae61b", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "dda0193a0fbd4947", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/qwen.json b/tests/fixtures/golden-install-parity/qwen.json index 3217ff6d3..1514e33cf 100644 --- a/tests/fixtures/golden-install-parity/qwen.json +++ b/tests/fixtures/golden-install-parity/qwen.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "bd054bb27beed2a7", "agents/gsd-eval-auditor.md": "57cc7458ab5de6b7", "agents/gsd-eval-planner.md": "01b665728dde4ccf", - "agents/gsd-executor.md": "988960899bd49c68", + "agents/gsd-executor.md": "6dcccfef842a49ac", "agents/gsd-framework-selector.md": "82ba6abea84226b7", "agents/gsd-integration-checker.md": "90835dbc7dfa1691", "agents/gsd-intel-updater.md": "3cc4f6ddd04676ec", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "83c66c7722e8b165", "agents/gsd-phase-researcher.md": "284e55a86ae46d7f", "agents/gsd-plan-checker.md": "c8a8fcc8ed38eff0", - "agents/gsd-planner.md": "75989c686d191143", + "agents/gsd-planner.md": "f0a5bede90f23be4", "agents/gsd-project-researcher.md": "b5baac64a15c85e2", "agents/gsd-research-synthesizer.md": "6cd9b501dc97bd50", "agents/gsd-roadmapper.md": "c357a77ab919e9e5", @@ -115,6 +115,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "3f6f5ee62d86f72d", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/trae.json b/tests/fixtures/golden-install-parity/trae.json index b32df012d..2734968b7 100644 --- a/tests/fixtures/golden-install-parity/trae.json +++ b/tests/fixtures/golden-install-parity/trae.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "b80f76874c04e515", "agents/gsd-eval-auditor.md": "470bf16303ec4d2e", "agents/gsd-eval-planner.md": "22334fde85723c9d", - "agents/gsd-executor.md": "2e92d53ec70b614f", + "agents/gsd-executor.md": "b3baa767abac0593", "agents/gsd-framework-selector.md": "7726fccc86bfeb50", "agents/gsd-integration-checker.md": "7cd2072984411c7f", "agents/gsd-intel-updater.md": "83de6ba9172891c3", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "b5d7a4abb1baecb9", "agents/gsd-phase-researcher.md": "2256f1f82212c757", "agents/gsd-plan-checker.md": "523119bd5d6599fe", - "agents/gsd-planner.md": "3cbce9388340c855", + "agents/gsd-planner.md": "fb330c599b9c1dac", "agents/gsd-project-researcher.md": "ddf7794e81300032", "agents/gsd-research-synthesizer.md": "a124b00271748d07", "agents/gsd-roadmapper.md": "493ef92b42b12cf4", @@ -115,6 +115,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "9a9383599893ea7e", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/windsurf.json b/tests/fixtures/golden-install-parity/windsurf.json index 63727749a..4aa8487a5 100644 --- a/tests/fixtures/golden-install-parity/windsurf.json +++ b/tests/fixtures/golden-install-parity/windsurf.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "56395dbdabf076f6", "agents/gsd-eval-auditor.md": "fb64fc5acf359747", "agents/gsd-eval-planner.md": "2049dac060d00eda", - "agents/gsd-executor.md": "5d56ba16562745d0", + "agents/gsd-executor.md": "45c4632bc67a12a2", "agents/gsd-framework-selector.md": "4b77eebbe9288d80", "agents/gsd-integration-checker.md": "4ffb37fb230c2b90", "agents/gsd-intel-updater.md": "a81d77c143c02108", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "ada0c169daa2f0ec", "agents/gsd-phase-researcher.md": "2a45ebde829555ec", "agents/gsd-plan-checker.md": "33fbf70b7b24eb1e", - "agents/gsd-planner.md": "c4072a4678c17485", + "agents/gsd-planner.md": "61ac0bd59b5b836a", "agents/gsd-project-researcher.md": "f6697b316b5995ba", "agents/gsd-research-synthesizer.md": "04036f38c1d373ea", "agents/gsd-roadmapper.md": "fb62e1e3de84b5f9", @@ -115,6 +115,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "18d50b6d12db830e", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "da39eace09a10743", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/golden-install-parity/zcode.json b/tests/fixtures/golden-install-parity/zcode.json index 056cd7184..5e498dae7 100644 --- a/tests/fixtures/golden-install-parity/zcode.json +++ b/tests/fixtures/golden-install-parity/zcode.json @@ -16,7 +16,7 @@ "agents/gsd-domain-researcher.md": "049f588663814fa2", "agents/gsd-eval-auditor.md": "54870d3b07433525", "agents/gsd-eval-planner.md": "552e9fa164c51ce8", - "agents/gsd-executor.md": "b49a6d92b2cd9831", + "agents/gsd-executor.md": "59fbb1e047b9a7c4", "agents/gsd-framework-selector.md": "8a795f230436ad2e", "agents/gsd-integration-checker.md": "c1760a0bbd4f7bf5", "agents/gsd-intel-updater.md": "944f1d903e2e9e09", @@ -25,7 +25,7 @@ "agents/gsd-pattern-mapper.md": "68ecefd60811a669", "agents/gsd-phase-researcher.md": "2235f61764d8e969", "agents/gsd-plan-checker.md": "bb38f345d3d41edc", - "agents/gsd-planner.md": "e76def94ab518216", + "agents/gsd-planner.md": "42f6e9832d5c2edc", "agents/gsd-project-researcher.md": "f572892f138734ff", "agents/gsd-research-synthesizer.md": "29949bf3f049a8f1", "agents/gsd-roadmapper.md": "840ac933e3b094f9", @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md": "b28fa3da6ae739a8", "gsd-core/references/planner-load-graph-context.md": "ca7a7af3f35ae61b", "gsd-core/references/planner-mvp-mode.md": "cfd535c9c545e73e", + "gsd-core/references/planner-preconditions.md": "4511829607ec9107", "gsd-core/references/planner-reviews.md": "dda0193a0fbd4947", "gsd-core/references/planner-revision.md": "86ba8a511f081f05", "gsd-core/references/planner-source-audit.md": "7de5bdb07232ce0b", diff --git a/tests/fixtures/install-tree/antigravity.json b/tests/fixtures/install-tree/antigravity.json index 310ffad32..18cf446a0 100644 --- a/tests/fixtures/install-tree/antigravity.json +++ b/tests/fixtures/install-tree/antigravity.json @@ -115,6 +115,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/augment.json b/tests/fixtures/install-tree/augment.json index a4b2e7922..de408512c 100644 --- a/tests/fixtures/install-tree/augment.json +++ b/tests/fixtures/install-tree/augment.json @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/claude-local.json b/tests/fixtures/install-tree/claude-local.json index 2f060468e..abd55e82d 100644 --- a/tests/fixtures/install-tree/claude-local.json +++ b/tests/fixtures/install-tree/claude-local.json @@ -185,6 +185,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/claude.json b/tests/fixtures/install-tree/claude.json index f0920a02e..39b9c7780 100644 --- a/tests/fixtures/install-tree/claude.json +++ b/tests/fixtures/install-tree/claude.json @@ -114,6 +114,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/cline.json b/tests/fixtures/install-tree/cline.json index be4c9c39e..36a075671 100644 --- a/tests/fixtures/install-tree/cline.json +++ b/tests/fixtures/install-tree/cline.json @@ -118,6 +118,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/codebuddy.json b/tests/fixtures/install-tree/codebuddy.json index fd8ed7e53..d4f673042 100644 --- a/tests/fixtures/install-tree/codebuddy.json +++ b/tests/fixtures/install-tree/codebuddy.json @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/codex.json b/tests/fixtures/install-tree/codex.json index d6f76ea04..cc170128b 100644 --- a/tests/fixtures/install-tree/codex.json +++ b/tests/fixtures/install-tree/codex.json @@ -221,6 +221,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/copilot.json b/tests/fixtures/install-tree/copilot.json index d7f1e3824..6b5df9763 100644 --- a/tests/fixtures/install-tree/copilot.json +++ b/tests/fixtures/install-tree/copilot.json @@ -116,6 +116,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/cursor.json b/tests/fixtures/install-tree/cursor.json index 2e3fa2eb1..a30363bca 100644 --- a/tests/fixtures/install-tree/cursor.json +++ b/tests/fixtures/install-tree/cursor.json @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/hermes.json b/tests/fixtures/install-tree/hermes.json index 58acc1d33..925431378 100644 --- a/tests/fixtures/install-tree/hermes.json +++ b/tests/fixtures/install-tree/hermes.json @@ -115,6 +115,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/kilo.json b/tests/fixtures/install-tree/kilo.json index 19c0fbe5d..4521e6168 100644 --- a/tests/fixtures/install-tree/kilo.json +++ b/tests/fixtures/install-tree/kilo.json @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/kimi.json b/tests/fixtures/install-tree/kimi.json index 100fc69eb..9f2615ec9 100644 --- a/tests/fixtures/install-tree/kimi.json +++ b/tests/fixtures/install-tree/kimi.json @@ -179,6 +179,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/opencode.json b/tests/fixtures/install-tree/opencode.json index ca22c4048..330121e16 100644 --- a/tests/fixtures/install-tree/opencode.json +++ b/tests/fixtures/install-tree/opencode.json @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/pi.json b/tests/fixtures/install-tree/pi.json index 677542e14..4baae4984 100644 --- a/tests/fixtures/install-tree/pi.json +++ b/tests/fixtures/install-tree/pi.json @@ -82,6 +82,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/qwen.json b/tests/fixtures/install-tree/qwen.json index 4a6132ada..041cd1410 100644 --- a/tests/fixtures/install-tree/qwen.json +++ b/tests/fixtures/install-tree/qwen.json @@ -115,6 +115,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/trae.json b/tests/fixtures/install-tree/trae.json index 3bff0d1ff..b48ca07e4 100644 --- a/tests/fixtures/install-tree/trae.json +++ b/tests/fixtures/install-tree/trae.json @@ -115,6 +115,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/windsurf.json b/tests/fixtures/install-tree/windsurf.json index e73fbe5cd..0054b2e3c 100644 --- a/tests/fixtures/install-tree/windsurf.json +++ b/tests/fixtures/install-tree/windsurf.json @@ -115,6 +115,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/fixtures/install-tree/zcode.json b/tests/fixtures/install-tree/zcode.json index ad72e0ff6..fa6044c57 100644 --- a/tests/fixtures/install-tree/zcode.json +++ b/tests/fixtures/install-tree/zcode.json @@ -186,6 +186,7 @@ "gsd-core/references/planner-interface-context.md", "gsd-core/references/planner-load-graph-context.md", "gsd-core/references/planner-mvp-mode.md", + "gsd-core/references/planner-preconditions.md", "gsd-core/references/planner-reviews.md", "gsd-core/references/planner-revision.md", "gsd-core/references/planner-source-audit.md", diff --git a/tests/precondition-element.test.cjs b/tests/precondition-element.test.cjs new file mode 100644 index 000000000..b1b6c2992 --- /dev/null +++ b/tests/precondition-element.test.cjs @@ -0,0 +1,233 @@ +// allow-test-rule: source-text-is-the-product [#1949] +// Agent .md, reference .md, and docs/reference/*.md files — their text IS what the +// runtime loads. Per CONTRIBUTING.md exception matrix, asserting these files +// document the contract tests the deployed surface, not derived +// behavior. The behavioral test (cmdVerifyPlanStructure) asserts the validator +// stays additive. Issue #1949. + +'use strict'; + +const { describe, test } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs'); + +const ROOT = path.resolve(__dirname, '..'); +const PLANNER = path.join(ROOT, 'agents', 'gsd-planner.md'); +const EXECUTOR = path.join(ROOT, 'agents', 'gsd-executor.md'); +const PLAN_MD_DOC = path.join(ROOT, 'docs', 'reference', 'plan-md.md'); +const PRECONDITIONS_REF = path.join(ROOT, 'gsd-core', 'references', 'planner-preconditions.md'); + +function read(rel) { + return fs.readFileSync(rel, 'utf-8').replace(/\r\n/g, '\n').replace(/\r/g, '\n'); +} + +// ─── Schema documentation (docs/reference/plan-md.md) ──────────────────────── + +describe('issue #1949: plan-md.md documents ', () => { + test('plan-md.md mentions as an optional task element', () => { + const doc = read(PLAN_MD_DOC); + assert.match( + doc, + //, + 'docs/reference/plan-md.md must document the element' + ); + }); + + test('plan-md.md states is optional and does not break plans that omit it', () => { + const doc = read(PLAN_MD_DOC); + assert.ok( + /optional/.test(doc) && /precondition/.test(doc), + 'plan-md.md must describe as optional' + ); + }); +}); + +// ─── Planner emission contract (agents/gsd-planner.md) ────────────────────── + +describe('issue #1949: gsd-planner.md declares emission', () => { + test('planner references the precondition reference file', () => { + const planner = read(PLANNER); + assert.ok( + planner.includes('planner-preconditions.md'), + 'gsd-planner.md must @-reference planner-preconditions.md (progressive disclosure)' + ); + }); + + test('planner is under the 49152-char cap after adding content', () => { + const planner = read(PLANNER); + assert.ok( + planner.length < 49152, + `gsd-planner.md is ${planner.length} chars, must be < 49152 (LF-normalized)` + ); + }); +}); + +// ─── Planner-preconditions reference file (progressive disclosure) ─────────── + +describe('issue #1949: planner-preconditions.md exists with the three emission cases', () => { + test('reference file exists', () => { + assert.ok(fs.existsSync(PRECONDITIONS_REF), `Missing: ${PRECONDITIONS_REF}`); + }); + + test('reference documents the user_setup emission case', () => { + const ref = read(PRECONDITIONS_REF); + assert.ok( + /user_setup/.test(ref) || /external service setup/i.test(ref), + 'planner-preconditions.md must document the user_setup / external-setup emission case' + ); + }); + + test('reference documents the prior-phase artifact emission case', () => { + const ref = read(PRECONDITIONS_REF); + assert.ok( + /prior.?phase artifact/i.test(ref) || /artifact from (a )?prior/i.test(ref), + 'planner-preconditions.md must document the prior-phase-artifact emission case' + ); + }); + + test('reference documents the env-var emission case', () => { + const ref = read(PRECONDITIONS_REF); + assert.ok( + /env(ironment)? var/i.test(ref), + 'planner-preconditions.md must document the env-var emission case' + ); + }); + + test('reference maps the contract triad (precondition / postcondition / invariant)', () => { + const ref = read(PRECONDITIONS_REF); + assert.ok( + /postcondition||/.test(ref), + 'planner-preconditions.md must map to existing postconditions (/)' + ); + }); +}); + +// ─── Executor assertion contract (agents/gsd-executor.md) ──────────────────── + +describe('issue #1949: gsd-executor.md asserts before task execution', () => { + test('executor mentions ', () => { + const exec = read(EXECUTOR); + assert.match( + exec, + //, + 'gsd-executor.md must reference ' + ); + }); + + test('executor routes an unmet precondition through checkpoint machinery (halt, no partial commit)', () => { + const exec = read(EXECUTOR); + assert.ok( + /precondition/i.test(exec) && /checkpoint/.test(exec), + 'gsd-executor.md must route unmet through checkpoint machinery' + ); + }); + + test('executor treats a met/absent precondition as a no-op (does not change flow)', () => { + const exec = read(EXECUTOR); + assert.ok( + /no.op|no visible change|continue/i.test(exec), + 'gsd-executor.md must state that a met or absent precondition produces no visible change' + ); + }); + + test('executor is under the 49152-char cap after adding content', () => { + const exec = read(EXECUTOR); + assert.ok( + exec.length < 49152, + `gsd-executor.md is ${exec.length} chars, must be < 49152 (LF-normalized)` + ); + }); +}); + +// ─── Behavioral test: validator stays additive (cmdVerifyPlanStructure) ────── +// +// `cmdVerifyPlanStructure` checks for PRESENCE of required tags. It must not +// reject unknown optional tags. This is the "does not break plans that omit it" +// plus "does not break plans that include it" guarantee from acceptance #1. +// Pattern mirrors tests/tracer-bullet.test.cjs (companion feature #1945). + +function planWith({ precondition = null } = {}) { + const lines = [ + '', + ' Task 1: Test', + ]; + if (precondition !== null) { + lines.push(` ${precondition}`); + } + lines.push( + ' src/x.ts', + ' Do the thing.', + ' echo ok', + ' Done', + '', + '', + ); + return [ + '---', + 'phase: 01-test', + 'plan: 01', + 'type: execute', + 'wave: 1', + 'depends_on: []', + 'files_modified: [src/x.ts]', + 'autonomous: true', + 'must_haves:', + ' truths:', + ' - "something is true"', + '---', + '', + '', + '', + ...lines, + '', + ].join('\n'); +} + +function verifyPlan(tmpDir, content) { + const rel = path.join('.planning', 'phases', '01-test', '01-01-PLAN.md'); + fs.mkdirSync(path.join(tmpDir, '.planning', 'phases', '01-test'), { recursive: true }); + fs.writeFileSync(path.join(tmpDir, rel), content); + const result = runGsdTools(`verify plan-structure ${rel}`, tmpDir); + assert.ok(result.success, `verify plan-structure failed to run: ${result.error}`); + return JSON.parse(result.output); +} + +describe('issue #1949: cmdVerifyPlanStructure accepts (additive)', () => { + test('plan with passes structural validation', (t) => { + const tmp = createTempProject(); + t.after(() => cleanup(tmp)); + + const out = verifyPlan(tmp, planWith({ precondition: 'OPENAI_API_KEY is set in the environment' })); + assert.strictEqual(out.valid, true, `plan with must be valid, errors: ${JSON.stringify(out.errors)}`); + assert.deepStrictEqual(out.errors, [], 'no validation path may reject a task'); + assert.ok( + !(out.warnings || []).some((w) => /precondition/i.test(w)), + 'nothing may flag the element specifically', + ); + }); + + test('plan without still passes structural validation (back-compat)', (t) => { + const tmp = createTempProject(); + t.after(() => cleanup(tmp)); + + const out = verifyPlan(tmp, planWith({ precondition: null })); + assert.strictEqual(out.valid, true, `plan without must be valid (back-compat), errors: ${JSON.stringify(out.errors)}`); + }); +}); + +// ─── Parity: docs/reference/plan-md.md and planner-preconditions.md agree ──── +// +// DEFECT.GENERATIVE-FIX-DIVERGENCE: two surfaces describing the same schema +// must agree on the canonical tag spelling. This is the parity guard against +// silent drift. + +describe('issue #1949: parity between plan-md.md and planner-preconditions.md', () => { + test('both surfaces spell the canonical tag ', () => { + const doc = read(PLAN_MD_DOC); + const ref = read(PRECONDITIONS_REF); + assert.ok(doc.includes(''), 'plan-md.md must spell '); + assert.ok(ref.includes(''), 'planner-preconditions.md must spell '); + }); +});