Skip to content

fix(templates): stop propose from skipping the specs artifact#1412

Open
clay-good wants to merge 11 commits into
mainfrom
fix/propose-includes-specs
Open

fix(templates): stop propose from skipping the specs artifact#1412
clay-good wants to merge 11 commits into
mainfrom
fix/propose-includes-specs

Conversation

@clay-good

@clay-good clay-good commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Closes #1260
Closes #788

Status: Ready to merge. Addresses @alfred-openspec's blocker and release-tracking follow-up (see the Review round section). One small additive change to the status --json output — each artifact now carries its requires edges — plus the propose/ff instruction text. No CLI behavior or schema change; the JSON change is backward-compatible (new field, existing consumers unaffected). Ships with a patch changeset.

Review round: @alfred-openspec's blocker (resolved)

The blocker: the loop told the agent to compute the required set as applyRequires plus everything it transitively requires, but status --json never carried those edges. At bb1d33a, a prewritten tasks.md reads done with no visible link to specs/design, so the agent could still stop with no spec. The hardcoded (spec-driven: proposal, specs, design, tasks) parenthetical was the only thing masking it — and it is wrong for any custom schema.

The fix (the "expose the edges" path @alfred offered): every artifact in status --json now carries its requires edge list for all statuses, including done. The loop derives the required set by walking those edges from applyRequires — computable from a single status call, for any schema, with no hardcoded list.

Proof — @alfred's exact repro, only tasks.md present:

$ openspec status --change add-user-auth --json   # artifacts, abbreviated
  proposal  status=ready    requires=[]
  design    status=blocked  requires=["proposal"]
  specs     status=blocked  requires=["proposal"]
  tasks     status=done     requires=["specs","design"]   <-- edge now visible on a done artifact

Walking the closure from applyRequires=["tasks"] using only these edges yields the required set {proposal, specs, design, tasks} and flags specs (with design, proposal) as still-missing — the agent creates them. Regression locked at the source level (instruction-loader.test.ts: a done tasks must still expose requires:["specs","design"]) and the template level.

Two more adversarial reviews hardened the instruction prose: the 4b heading no longer restates the apply.requires-only stop condition, the skip decision now tells the agent to read the artifact's instruction field before skipping (specs is never optional), and the walk's seed/source (status --json) are named explicitly.

What was wrong

/opsx:propose could finish and declare a change "ready to implement" with no spec written at all — in a spec-driven tool. Two independent reports: #1260 and #788. /opsx:ff reproduced it too.

Two things combined:

  1. The propose preamble listed only proposal.md, design.md, tasks.md. The default spec-driven schema defines four artifacts, and tasks requires specs. The first thing the agent read told it specs was not part of the job.
  2. Completeness was defined as applyRequires, which is ["tasks"]. An artifact becomes done the moment a matching file exists (detectCompleted), so writing tasks.md early flipped tasks from blocked to done and satisfied the stop condition. The Guardrails section said the same thing outright: "Create ALL artifacts needed for implementation (as defined by schema's apply.requires)".

How it was fixed

The preamble now names specs/<capability>/spec.md and is framed as schema-derived rather than a fixed three. Step 4b and the guardrail are rewritten around the required setapplyRequires plus everything it transitively requires:

b. **Continue until every artifact the apply phase depends on exists**
   - After creating each artifact, re-run `openspec status --change "<name>" --json`
   - The required set is `applyRequires` plus everything they transitively `requires`
     (spec-driven: proposal, specs, design, tasks). Leave artifacts outside that set alone
   - `status` is file-existence only, so an `applyRequires` artifact reading `done` does NOT
     mean its dependencies exist - writing `tasks.md` early marks `tasks` done while `specs`
     was never written
   - Create every artifact in the required set that is missing, then re-check - creating one
     can unblock others
   - Skip one only when its own `instruction` says it is conditional (spec-driven's
     `design.md`); tell the user, and do not reconsider it
   - Dependencies are enablers, not gates: if a required artifact is still `blocked` only
     because you skipped a conditional dependency, write it anyway
   - Stop when every artifact in the required set is `done` or was deliberately skipped

Applied identically to propose.ts and ff-change.ts (skill and command bodies each), since they run byte-identical loops.

Design notes

  • Nothing is gated on blocked. An earlier draft said "never write a blocked artifact" — that deadlocks propose, because tasks requires both specs and design, and docs/concepts.md:455 says "Dependencies are enablers, not gates… You can skip design if you don't need it." A change with no design.md validates clean. The loop instead states the permission explicitly.
  • Skipping is anchored to the instruction field. specs must not be skippable (openspec validate rejects a change with no deltas), but "required" is not machine-readable — the graph has tasks requiring both. The artifact's own instruction is the only signal that distinguishes them: spec-driven's design opens with "create only if any apply"; specs says nothing of the kind. A schema-level optional: true field would be the durable fix — worth a follow-up.
  • The required set is a closure, not "everything ready." A custom schema can define artifacts outside the apply path (a post-implementation retro, say); propose has no business creating those.

Replication / proof

The failure chain, against dist/. Write proposal.md and design.md, skip specs, write tasks.md:

--- before writing tasks.md ---
applyRequires: ['tasks']
  proposal done
  design   done
  specs    ready
  tasks    blocked ['specs']

--- agent skips specs and writes tasks.md ---
  specs    ready
  tasks    done          <-- flipped by file existence alone

Stop condition satisfied, yet:

$ openspec status --change add-user-auth
Progress: 3/4 artifacts complete

[x] proposal
[x] design
[ ] specs
[x] tasks

$ ls openspec/changes/add-user-auth/specs
ls: No such file or directory

Four scenarios traced against the final text: the #1260 state (specs now created), a docs-only change with design skipped (terminates, no deadlock — verified tasks blocked ['design'] with nothing ready), a custom schema with an out-of-closure artifact (left alone), and a user hand-writing tasks.md first (the set check catches the rest).

test/core/templates/propose.test.ts — 9 cases across all four bodies, one per guarantee. The preamble case reads schemas/spec-driven/schema.yaml via loadSchema() and asserts every artifact id it defines appears, so this drift cannot recur silently when the schema changes.

Full suite: 2036 passed, zero unrelated failures. The only failures are the 17 known environment-only zsh-installer cases (Oh My Zsh), documented in CLAUDE.md.

Notes

  • No breaking changes. The one code change is additive: a requires field on each artifact in status --json (documented in docs/agent-contract.md and pinned by a new cli-artifact-workflow spec scenario). The human-readable status renderer is untouched. Plus the regenerated skills/openspec-propose/SKILL.md and skills/openspec-ff-change/SKILL.md and six golden hashes; all 12 skills verified to regenerate byte-identically.
  • Release-tracking. A patch changeset (.changeset/propose-includes-specs.md) covers both the propose/ff fix and the additive status --json requires field.
  • ff-change.ts is included deliberately — it runs the byte-identical loop and reproduced the same spec-less change via /opsx:ff.
  • Textual conflict with feat(validate): accept zero-delta changes that declare skip_specs #1399 is expected. That PR rewrites the same step-4b lines to accept a new status: "skipped" for skip_specs changes. Complementary: this one defines what completeness means, feat(validate): accept zero-delta changes that declare skip_specs #1399 adds a declarative way to mark specs intentionally absent. Whichever lands second takes a trivial resolution.
  • Complementary to fix(apply): fail with exit 1 when apply instructions are blocked #1250, which makes openspec instructions apply exit 1 when blocked — downstream detection in src/commands/; this is upstream prevention in src/core/templates/.
  • Pre-existing issues found while reviewing, not touched here: docs/commands.md:245,259 now understate the loop's behavior; codebuddy/crush/lingma/qoder adapters emit name: OPSX: <X> unescaped, which breaks YAML frontmatter for every command. Happy to file both.
  • No Specs generated after /opsx:propose #1260 is an exact match with a correct root-cause analysis from the reporter. opsx:propose cannot create spec.md #788 reports the same symptom with no repro attached — closing it on the strength of the shared mechanism; happy to unlink if you would rather wait for reporter confirmation.

🤖 Generated with Claude Code

The propose skill and command opened by telling the agent it would create
"proposal.md, design.md, tasks.md" — omitting specs entirely, even though
the default spec-driven schema defines four artifacts and tasks requires
specs.

Artifact status is derived from file existence (detectCompleted), so an
agent that wrote tasks.md while tasks was still blocked flipped it to
"done" and satisfied the workflow's stop condition ("all applyRequires
artifacts are done") with specs never created.

Two guidance fixes in propose.ts, applied to both the skill and command
bodies:
- the opening list now names specs/<capability>/spec.md and frames the
  list as schema-derived rather than fixed
- step 4b forbids writing an artifact whose status is blocked, pointing
  at its missingDeps first

Closes #1260
Closes #788

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@clay-good
clay-good requested a review from TabishB as a code owner July 21, 2026 19:35
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The propose and fast-forward templates now enumerate schema-derived artifacts, resolve output paths, and check for remaining ready artifacts before stopping. Tests validate artifact listings, guard ordering, output-path guidance, blocked-status wording, and updated template hashes.

Changes

Propose and fast-forward workflow

Layer / File(s) Summary
Schema artifact contracts
skills/openspec-propose/SKILL.md, src/core/templates/workflows/propose.ts
The propose instructions list proposal.md and specs/<capability>/spec.md as default change artifacts and identify the spec as a delta inside the change directory.
Artifact creation and completion checks
skills/openspec-ff-change/SKILL.md, skills/openspec-propose/SKILL.md, src/core/templates/workflows/ff-change.ts, src/core/templates/workflows/propose.ts
Artifact loops describe writing resolved outputs, treating context and rules as constraints, rechecking status, and creating or explaining remaining ready artifacts before stopping.
Template regression and parity validation
test/core/templates/propose.test.ts, test/core/templates/skill-templates-parity.test.ts
Tests verify schema-derived artifact listings, delta-spec wording, ready-sweep ordering, glob-path resolution guidance, blocked-status wording, and updated hashes.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • Issue 1260 — Addresses propose stopping after apply-required artifacts are done while specs remain uncreated.
  • Issue 788 — Concerns propose failing to create capability specs.
  • Issue 1212 — Covers creating and verifying all schema artifacts in propose and fast-forward workflows.

Possibly related PRs

Suggested reviewers: tabishb, alfred-openspec

Sequence Diagram(s)

sequenceDiagram
  participant ProposeOrFfWorkflow
  participant OpenSpecStatus
  participant ChangeArtifacts
  ProposeOrFfWorkflow->>OpenSpecStatus: Run status --json
  OpenSpecStatus-->>ProposeOrFfWorkflow: Return artifact states
  ProposeOrFfWorkflow->>ChangeArtifacts: Create artifact at resolvedOutputPath
  ChangeArtifacts-->>OpenSpecStatus: File exists
  OpenSpecStatus-->>ProposeOrFfWorkflow: Mark artifact done and expose remaining ready artifacts
  ProposeOrFfWorkflow->>ChangeArtifacts: Create remaining ready artifacts
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes address #1260 and #788 by making propose/ff sweep remaining ready artifacts, including specs, before stopping.
Out of Scope Changes check ✅ Passed The extra ff template, test, and parity-hash updates support the same workflow fix and don't introduce unrelated scope.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: preventing propose from skipping the specs artifact.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/propose-includes-specs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…ocked

Review of the first commit found the blocked-artifact rule would deadlock
propose. In spec-driven, tasks requires [specs, design], so tasks is
blocked whenever design is absent — but docs/concepts.md states
"Dependencies are enablers, not gates. You can skip design if you don't
need it", the schema says to create design.md "only if any apply", and a
change with no design.md validates clean. Forbidding writes to blocked
artifacts would have left propose unable to finish those changes.

Replaced with a stop-time sweep that targets the actual failure without
gating anything: before stopping, create any artifact still `ready` or
tell the user which one is being skipped and why. specs is caught because
it is still `ready` at that point; design stays legitimately skippable.

Also from review:
- apply the same guard to ff-change.ts, which runs the byte-identical
  loop and reproduced the same spec-less change via /opsx:ff
- tell the agent to resolve a glob resolvedOutputPath to a concrete path
  (specs generates specs/**/*.md, so a literal write creates a `**` dir)
- mark the spec bullet as a delta inside the change directory, so it
  cannot be read as the main spec under openspec/specs/
- harden the ordering assertion so a missing guard cannot satisfy it

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/templates/workflows/propose.ts`:
- Around line 79-82: Require all required ready artifacts, including specs, to
be created before stopping; only explicitly optional artifacts may be skipped
with an explanation. Apply this guard in src/core/templates/workflows/propose.ts
at lines 79-82 and 195-198, src/core/templates/workflows/ff-change.ts at lines
69-72 and 175-178, and update the generated skills in
skills/openspec-propose/SKILL.md at line 80 and
skills/openspec-ff-change/SKILL.md at lines 69-70. Update
test/core/templates/propose.test.ts at lines 86-90 to verify required artifacts
cannot be skipped while optional artifacts remain skippable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bfd44dc8-069b-4eee-8a72-1f54cb9b4a7c

📥 Commits

Reviewing files that changed from the base of the PR and between 6ea91d8 and 6c02889.

📒 Files selected for processing (6)
  • skills/openspec-ff-change/SKILL.md
  • skills/openspec-propose/SKILL.md
  • src/core/templates/workflows/ff-change.ts
  • src/core/templates/workflows/propose.ts
  • test/core/templates/propose.test.ts
  • test/core/templates/skill-templates-parity.test.ts

Comment thread src/core/templates/workflows/propose.ts Outdated
Third review round:
- the sweep was single-pass, so creating a ready artifact could unblock
  others that then went unwritten; it now repeats until none remain
- "every artifact your schema requires" collided with the applyRequires
  field the agent reads 35 lines later, which literally means ["tasks"];
  say "the artifacts your schema defines" instead
- the negative test pinned the exact rejected sentence, so any reworded
  prohibition would have passed; match the shape instead (verified
  against four phrasings of the deadlock rule)
- drop "immediately" from a test title that only asserts ordering

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/openspec-ff-change/SKILL.md`:
- Line 70: Update the artifact-completion guidance in
skills/openspec-ff-change/SKILL.md at line 70 and
skills/openspec-propose/SKILL.md at line 80 so only explicitly optional
artifacts may be skipped; require every schema-required artifact to be created
before completion, including specs/<capability>/spec.md, while preserving the
existing repeat-until-none-ready behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4972c885-3ae3-4d69-9c66-08de858feffb

📥 Commits

Reviewing files that changed from the base of the PR and between 6c02889 and a8bab6d.

📒 Files selected for processing (6)
  • skills/openspec-ff-change/SKILL.md
  • skills/openspec-propose/SKILL.md
  • src/core/templates/workflows/ff-change.ts
  • src/core/templates/workflows/propose.ts
  • test/core/templates/propose.test.ts
  • test/core/templates/skill-templates-parity.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • test/core/templates/skill-templates-parity.test.ts
  • src/core/templates/workflows/propose.ts
  • src/core/templates/workflows/ff-change.ts
  • test/core/templates/propose.test.ts

Comment thread skills/openspec-ff-change/SKILL.md Outdated
…ional

CodeRabbit flagged that the sweep's escape hatch let the agent skip any
remaining ready artifact, including specs — which openspec validate
requires ("Change must have at least one delta").

"Required" is not machine-readable: the graph has tasks requiring both
specs and design, so keying off the dependency edges would force design
again and reintroduce the deadlock. The artifact's own instruction text
does carry the distinction — spec-driven's design opens with "When to
include design.md (create only if any apply)" while specs is
unconditional — so the skip permission is anchored there instead.

Test asserts both halves: the conditional wording is present and no
unconditional skip escape hatch remains.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/openspec-ff-change/SKILL.md`:
- Line 70: Update the artifact sweep instructions to track IDs of explicitly
skipped conditional artifacts, such as spec-driven design.md, and exclude those
IDs when checking for remaining ready artifacts. Continue sweeping until no
unskipped artifacts remain ready, while still requiring every applyRequires
artifact to reach done status.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 951bbf16-c1f5-42b1-ba1d-aee48b7493da

📥 Commits

Reviewing files that changed from the base of the PR and between a8bab6d and 7e31d8c.

📒 Files selected for processing (6)
  • skills/openspec-ff-change/SKILL.md
  • skills/openspec-propose/SKILL.md
  • src/core/templates/workflows/ff-change.ts
  • src/core/templates/workflows/propose.ts
  • test/core/templates/propose.test.ts
  • test/core/templates/skill-templates-parity.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/core/templates/workflows/ff-change.ts
  • src/core/templates/workflows/propose.ts
  • test/core/templates/skill-templates-parity.test.ts
  • test/core/templates/propose.test.ts

Comment thread skills/openspec-ff-change/SKILL.md Outdated
CodeRabbit caught the interaction between the previous two commits: a
conditional artifact that is skipped never gets a file, so it stays
`ready` forever and "repeat until none remain" would not terminate for
any change that legitimately omits design.md.

The sweep now repeats until only skipped artifacts remain, and skipping
an artifact takes it out of later sweeps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/openspec-ff-change/SKILL.md`:
- Around line 70-71: Update the final completion summaries in
skills/openspec-ff-change/SKILL.md lines 84-88 and
skills/openspec-propose/SKILL.md lines 94-98 to state that all required
artifacts are complete, and explicitly list any conditional artifacts skipped
during the workflow; ensure the summaries no longer claim that every artifact
was created.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1f305fc9-de59-4545-b65b-9e2703028f57

📥 Commits

Reviewing files that changed from the base of the PR and between 7e31d8c and 18a6c12.

📒 Files selected for processing (6)
  • skills/openspec-ff-change/SKILL.md
  • skills/openspec-propose/SKILL.md
  • src/core/templates/workflows/ff-change.ts
  • src/core/templates/workflows/propose.ts
  • test/core/templates/propose.test.ts
  • test/core/templates/skill-templates-parity.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/core/templates/workflows/propose.ts
  • src/core/templates/workflows/ff-change.ts
  • test/core/templates/skill-templates-parity.test.ts
  • test/core/templates/propose.test.ts

Comment thread skills/openspec-ff-change/SKILL.md Outdated
clay-good and others added 2 commits July 21, 2026 16:37
Now that a conditional artifact can be legitimately skipped, the closing
summary claiming "All artifacts created!" would be false. Report the
required set instead, and list any conditional artifact that was skipped
alongside the ones created.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three adversarial reviews converged on the same defects, two of which I
reproduced against the CLI.

Deadlock (blocker): skipping design left tasks blocked forever. Nothing
was ready, the sweep terminated, and the stop condition could never be
met — and the word "blocked" appeared nowhere in the skill, so no step
authorized writing it. The loop now states outright that dependencies
are enablers, not gates: a required artifact blocked only by a skipped
conditional gets written anyway.

Over-scoping: sweeping every `ready` artifact told propose to write
artifacts outside the apply closure. Reproduced with a custom schema
carrying a post-implementation `retro`. The required set is now
applyRequires plus its transitive requires, and everything else is
explicitly left alone.

Stale guardrail: "Create ALL artifacts needed for implementation (as
defined by schema's `apply.requires`)" encoded the exact premise this
fix refutes, and none of the earlier commits touched it.

Also: step 4b heading and its closing bullet contradicted the guard
above them; the 498-char bullet is now six short ones; the preamble and
glob sentences are tightened. Tests drop three vacuous or wording-pinned
assertions for positive checks on each guarantee.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One blocker before approval: status --json does not expose each artifact's requires edges, so the new instructions cannot reliably compute the transitive required set when an apply artifact is already done. I reproduced this at bb1d33a with only tasks.md present: the JSON reports applyRequires: ["tasks"] and tasks: done, but no edge from tasks to specs/design; please derive the closure through instructions (or expose the edges) and add this prewritten-tasks regression.

…d set

alfred's PR #1412 blocker: the propose/ff loop told the agent to build the
"required set" from `applyRequires` plus everything it transitively `requires`,
but `status --json` never carried those edges. A prewritten `tasks.md` reads
`done` with no visible link to specs/design, so the agent could still stop
without a spec. The only thing making it work was a hardcoded schema list in
the instruction text, which is wrong for any custom schema.

Fix (alfred's "expose the edges" path): every artifact in `status --json` now
carries its `requires` edge list for all statuses, including `done`. The loop
derives the required set by walking those edges from `applyRequires` -
computable from a single status call, for any schema. Proven end-to-end: with
only tasks.md present, `tasks` reports `requires:["specs","design"]` and the
closure walk correctly flags specs/design/proposal as still-missing.

Also hardens the agent instructions from three adversarial reviews:
- 4b heading named the buggy stop condition ("every artifact the apply phase
  depends on"); now names the required set explicitly
- skip decision now tells the agent to fetch `openspec instructions` and read
  the `instruction` field before skipping (specs is never optional)
- names the walk's seed (`from those`) and the source command (`status --json`,
  since instructions calls the edges `dependencies`)
- completion headline no longer claims "all created" when a conditional was skipped

Contract doc (agent-contract.md), the cli-artifact-workflow spec, and tests
(source-level prewritten-tasks regression + template guards) updated; skills
regenerated and six golden hashes refreshed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 21, 2026

Copy link
Copy Markdown

Deploying openspec-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: c90dea9
Status: ✅  Deploy successful!
Preview URL: https://38d25b18.openspec-docs.pages.dev
Branch Preview URL: https://fix-propose-includes-specs.openspec-docs.pages.dev

View logs

@clay-good

Copy link
Copy Markdown
Collaborator Author

@alfred-openspec — fixed at 5a95821, taking the "expose the edges" path you offered.

status --json now emits each artifact's requires edge list for every status, including done. Your exact repro, only tasks.md present:

  proposal  status=ready    requires=[]
  design    status=blocked  requires=["proposal"]
  specs     status=blocked  requires=["proposal"]
  tasks     status=done     requires=["specs","design"]

The edge from tasksspecs/design is now visible on the done artifact, so the transitive required set is computable from a single status call — no instructions walk, no hardcoded schema list. Walking the closure from applyRequires=["tasks"] yields {proposal, specs, design, tasks} and flags specs as still-missing, so the agent creates it.

Regression added exactly where you asked — source level in instruction-loader.test.ts: with only tasks.md on disk, tasks reads done and requires must contain ["specs","design"] (it fails without the source change). Plus template-level guards.

While here, two more adversarial review passes hardened the instruction prose: the 4b heading no longer restates the apply.requires-only stop condition, and the skip step now tells the agent to fetch openspec instructions <id> --json and confirm the instruction field marks an artifact optional before skipping (specs never qualifies). Contract doc + a new cli-artifact-workflow spec scenario pin the new field. Full suite green (2040 passed; the only failures are the documented env-only zsh-installer cases).

…shape

The single-star-glob status/apply consistency test pins the exact status JSON
artifact shape with toEqual. Adding the `requires` edge to every artifact made
the actual object a superset of the expected, failing CI on all platforms
(local runs masked it as an env-only zsh-installer failure). Include
`requires: []` in the expected shape so the test reflects the new contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Third adversarial-review round on the final state. Two doc/prose findings:

1. Step 4's title still read "Create artifacts in sequence until apply-ready" —
   the bug's own vocabulary. In the prewritten-tasks case the change is already
   apply-ready when step 4 begins (applyRequires=["tasks"], tasks done), so a
   literal agent anchoring on the title could create nothing and stop — the exact
   early-stop this PR kills. A prior round fixed the 4b sub-heading but left the
   step title. Retitled to "Create every artifact in the required set" (all four
   propose/ff bodies), which also reframes the step around the required set so 4b
   is the driver. Pinned by a new template test.

2. docs/cli.md's `status --json` example still omitted the `requires` field
   (agent-contract.md was updated last round, this example was missed). Filled in
   with real values from the CLI for that exact scenario.

Skills regenerated; six golden hashes refreshed. Full suite 2042 pass; only the
17 env-only zsh-installer failures remain (CI-green). The correctness and
tests/hygiene review passes were clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original blocker is fixed: the exact-head build, 123 focused tests, clean skill regeneration, and prewritten-tasks.md reproduction all pass. One release-tracking fix remains before approval: this now adds artifacts[].requires to the public status --json contract and changes shipped workflow templates, so please add a patch changeset and refresh the PR description's now-stale template-only/no-JSON-contract claims.

…requires field

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original dependency-closure blocker and release-tracking follow-up are fixed at c259a6f: the prewritten-tasks.md case now exposes every requires edge, and the retitled create step plus CLI/contract docs consistently drive the full required set. Exact-head build, 123 focused tests, clean skill regeneration, the manual reproduction, release tracking, and the full CI/CodeQL matrix all pass.

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved at c259a6f. The new requires edges close the prewritten-tasks.md hole, the workflow guidance and generated skills are aligned, and the public contract, regression coverage, patch changeset, and exact-head CI all match the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No Specs generated after /opsx:propose opsx:propose cannot create spec.md

2 participants