validate

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 6, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package validate implements the custom-artifact structural checks spec-lifecycle.md §3.3 wires into each gate's pre-check ("lifecycle validate --stage <s>") and implementation-plan.md §2.3 assigns to M2. On top of internal/spec's delta-grammar parser (which this package delegates to for every specs/**/spec.md delta file — one grammar code path, never duplicated: this package never re-implements a rule ParseDelta already enforces), it checks the three artifacts the OpenSpec format itself has no opinion on:

  • proposal.md: a "---"-delimited YAML frontmatter block is present, and its `issue` field is a non-empty string (spec-lifecycle.md §4's proposal row, §10's sourceTracking join key).
  • design.md: an explicit NFR-discharge section ("## NFR Discharge", case/hyphen-insensitive) is present (spec-lifecycle.md §4's design row, §4.1's NFR routing rule, §7's ADR-proposal seam).
  • tasks.md: every "## Milestone <n>: <name>" block carries the four fixed labels **Goal** / **Deliverables** / **Validation contract** / **Steps**, and Validation contract has at least one non-blank line under it (spec-lifecycle.md §4.2, verbatim).

Stage -> artifact mapping

Derived from spec-lifecycle.md §4's artifact table (its Stage column) and §3.3's gate mechanics: each stage's `lifecycle validate --stage <s>` checks only the artifact(s) *produced during* that stage. An earlier stage's artifacts were already gated approved by the time a later stage runs — the schema's requires: DAG (internal/schema) already establishes their existence is a precondition, not something a later stage's validate call needs to re-check.

refine  -> proposal.md + every changes/<change>/specs/**/spec.md delta
design  -> design.md
plan    -> tasks.md

(The bug flow's compressed profile — spec-lifecycle.md §8 — and its repro/fix stage names are out of scope for this package; M2 covers only the three feature-flow stages. A future bug-flow validate call is a straightforward extension of the same shape, deferred to whichever milestone wires the bug flow's gate records.)

A stage whose artifact (or, for refine, whose specs/ delta directory) does not exist at all is reported as a single "missing_artifact" Finding, not a read error — `lifecycle validate` can legitimately run before an agent has produced anything yet, as a pre-check sanity probe (spec-lifecycle.md §3.3 step 2).

Warning-level polish

One additional, WARNING-only (never error-, never exit-code-affecting) heuristic runs over each specs/**/spec.md delta: a "### Requirement:" heading that sits under an H2 section OpenSpec's own delta grammar does not recognize (i.e. not one of ADDED/MODIFIED/REMOVED/RENAMED Requirements) is silently ignored by both the real oracle and this package's own internal/spec.ParseDelta (see internal/spec/doc.go's divergence table) — a genuine "requirement-shaped drop with no diagnostic" that the M1 verifier flagged. This package's warning scan is a plain, non-fence-mask-aware line scan (deliberately simpler than internal/spec's own header detection): it may rarely false-positive on a "### Requirement:"-shaped line inside a fenced code sample, which is acceptable for an advisory that never affects validity or the exit code, and it does not change internal/spec's parsing behavior or the conformance corpus's results in any way.

Index

Constants

View Source
const (
	ChangeTypeFeature = "feature"
	ChangeTypeBug     = "bug"
)

Change type vocabulary (spec-lifecycle.md §8, §0's Stage glossary). Recorded at intake in proposal.md's frontmatter (this milestone's own decision — see ProposalMeta's doc comment) and consumed by internal/approve/internal/status to key the bug-vs-feature stage set (implementation-plan.md §2.11).

Variables

Stages lists every recognized Stage value, in gate order — the set `lifecycle validate --stage` accepts.

Functions

func ArtifactsForStage

func ArtifactsForStage(stage Stage) []string

ArtifactsForStage returns the artifact path(s) — relative to a change folder — that `stage` gates (the package doc's Stage -> artifact table). Useful for a caller (e.g. the CLI) that wants to name what it's about to check without duplicating the mapping.

func HasArtifact

func HasArtifact(dir, name string) bool

HasArtifact reports whether the named file (e.g. "tasks.md") exists directly under dir.

func HasSpecsDeltas

func HasSpecsDeltas(dir string) bool

HasSpecsDeltas reports whether dir/specs contains at least one spec.md delta file — used by internal/approve to decide whether a promoted bug's "repro" gate should also validate a specs/ delta (spec-lifecycle.md §8: "If the repro reveals mis-specced behavior... gate it like a feature refine").

Types

type Finding

type Finding struct {
	File     string   `json:"file"`
	Line     int      `json:"line,omitempty"`
	Kind     string   `json:"kind"`
	Message  string   `json:"message"`
	Severity Severity `json:"severity"`
}

Finding is one precise, position-anchored validation result: which file, which line (0 if not tied to a single line), a stable machine Kind a caller can switch on without matching prose, and a human-readable Message.

func Change

func Change(dir string, stage Stage) ([]Finding, error)

Change validates the artifact(s) a stage gates inside a single change folder (dir — e.g. "openspec/changes/042-user-auth", absolute or relative; every Finding's File is derived from dir exactly as given). Findings are returned in a stable order (by File, then Line); a non-nil error means validation could not even be attempted (e.g. a change directory that exists but isn't readable) — distinct from findings, which are validation *results*, not failures to run.

func Design

func Design(dir string) ([]Finding, error)

Design exports validateDesign — see Proposal's doc comment.

func Plan

func Plan(dir string) ([]Finding, error)

Plan exports validatePlan — see Proposal's doc comment. Used directly by internal/approve's bug-flow "fix" gate when tasks.md is present (spec-lifecycle.md §8: "tasks.md optional").

func Proposal

func Proposal(dir string) ([]Finding, error)

Proposal exports validateProposal for callers outside this package that need proposal.md's own structural check without going through Change's three-stage dispatch (internal/approve's bug-flow "repro" gate, which checks proposal.md but — unlike StageRefine — does not always require a specs/ delta; spec-lifecycle.md §8).

func SpecsDeltas

func SpecsDeltas(dir string) ([]Finding, error)

SpecsDeltas exports validateSpecsDeltas — see Proposal's doc comment.

type ProposalMeta

type ProposalMeta struct {
	Issue      string
	DesignSkip bool
	Type       string
}

ProposalMeta is the intake-time metadata proposal.md's frontmatter carries beyond the pass/fail structural check validateProposal (Proposal) already performs: the sourceTracking join key, a proposed design-skip, and the change type.

Type is spec-lifecycle.md §8/§2.11's "change type recorded at intake" — the spec names the concept ("status/guard/archive gate-checks key off the change type recorded at intake") but does not pin exactly where that's recorded. This package decides: proposal.md's frontmatter, a `type: feature|bug` field alongside the already-load-bearing `issue` and `designSkip` fields (schema.yaml's proposal artifact documents it for the same reason). Absent (or non-string) is ChangeTypeFeature — a proposal.md written before this decision landed still parses.

func ReadProposalMeta

func ReadProposalMeta(dir string) (ProposalMeta, error)

ReadProposalMeta reads dir/proposal.md's frontmatter fields. It does NOT itself validate structure — call Proposal(dir) (or Change(dir, StageRefine)) first if that matters to the caller. A missing file or unparsable/absent frontmatter yields a zero ProposalMeta (Type defaults to ChangeTypeFeature) and a nil error: this is metadata extraction for an already-validated (or not-yet-existing) artifact, not a second validation pass.

type Severity

type Severity string

Severity distinguishes a hard validation failure (fails the artifact, and — at the CLI — the process) from an advisory that never does.

const (
	SeverityError   Severity = "error"
	SeverityWarning Severity = "warning"
)

The two recognized Severity values.

type Stage

type Stage string

Stage is one of the three gated stages spec-lifecycle.md §3 defines for the default feature flow.

const (
	StageRefine Stage = "refine"
	StageDesign Stage = "design"
	StagePlan   Stage = "plan"
)

The three recognized Stage values, in gate order.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL