Skip to content

A schema's apply block is never validated: a typo silently disables the apply gate or blocks it forever #1867

Closed

Description

@dwin-gharibi

Description

parseSchema checks every artifact's requires, but never the apply block.
openspec schema validate therefore reports a schema as valid when
apply.requires names an artifact id that does not exist, or when
apply.tracks names a file no artifact generates. Nothing reports the typo
later either:

  1. Unknown apply.requires id: the apply gate turns off. The id is skipped,
    so apply reports ready and tells the agent "All required artifacts
    complete. Proceed with implementation." with only a proposal written.
  2. Unknown apply.tracks path: apply blocks forever. Apply waits for a file
    nothing generates, and its remedy prints a literal <artifact> placeholder.
    Meanwhile openspec list counts a different file (tasks.md).

The code claims the opposite: src/commands/schema.ts:230-231 says "Dependency
graph validation is already done by parseSchema (it throws on cycles and
invalid references)".

Reproduction

A project schema copied from spec-driven (openspec/schemas/myflow), with
openspec/config.yaml set to schema: myflow.

A: typo in apply.requires. With apply: replaced by
requires: [desgin] and only proposal.md written:

openspec schema validate myflow
  ✓ Schema 'myflow' is valid
openspec instructions apply --change c --json
  state=ready missingArtifacts=None
  instruction=All required artifacts complete. Proceed with implementation.

The control, requires: [design], gives state=blocked missingArtifacts=['design'].

B: typo in apply.tracks. With requires: [tasks], tracks: task.md and
every artifact written:

openspec schema validate myflow
  ✓ Schema 'myflow' is valid
openspec status --change c --json        isPlanningComplete=True
openspec instructions apply --change c   state=blocked
  The task.md file is missing and must be created.
  Create it with `openspec instructions <artifact> --change c` ...
openspec list --json                     1/2 in-progress

Expected

schema validate rejects an apply.requires id or an apply.tracks path that
no artifact declares, the same way it rejects an invalid artifact requires.
docs/agent-contract.md says missingArtifacts "is what apply blocks on (the
schema's apply.requires)", so apply must never treat an unknown requirement
as satisfied.

Root cause

  • src/core/artifact-graph/schema.ts: parseSchema runs
    validateRequiresReferences(schema.artifacts) and never looks at
    schema.apply.
  • src/commands/workflow/instructions.ts: the missing-artifact check runs
    if (artifact && ...), so an unknown id counts as present, and
    collectMissingPrerequisites skips it with if (!artifact) continue.
  • For tracks, findArtifactIdFor returns undefined, and the remedy falls
    back to the <artifact> placeholder.

Impact

Only projects with a custom schema are affected, but for them a one-character
typo either turns off the gate that stops an agent implementing before planning
is done, or leaves every change blocked behind a remedy that cannot be followed.
The command meant to catch it says the schema is valid.

Environment

  • OpenSpec 1.13.0 (reproduced on the published npm package and on a build of
    main @ 9d4e597)
  • Node v22, Linux

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions