Skip to content

spec-drift-finder

Spec drift finder — specs vs code, a person decides

Splits every spec (OpenSpec, ADRs, SPEC docs, API contracts) into atomic requirements, maps each to code, gets a calibrated verdict with evidence, asks a person change-code-or-change-spec per item, makes the minimal fix, re-proves each requirement conforms, and opens one PR behind approval.

Source templates/spec-drift-finder/workflow.yaml
Category development
Trigger manual (wfx run) · schedule 0 7 * * 1
Steps 15
Human approval before publish
Providers named gemini
Terminal window
wfx templates spec-drift-finder
wfx new spec-drift-finder --as my-spec-drift-finder
wfx dryrun my-spec-drift-finder

Finds every spec in the repository, splits it into atomic requirements with file:line, maps each requirement to the code that implements it (one mapper per spec file, coverage proven by code), classifies each with a calibrated verdict over evidence read from the files, recommends change_code / change_spec / clarify with the smallest edit, and asks a person to decide every item that touches a spec. Makes the minimal code fix (with a test) or spec edit (an OpenSpec change delta where that is the convention), proves the suite stays green and every changed requirement now conforms, has a different model review it, and opens a PR with the requirement → verdict → decision → change table.

  • extra_specs: documents this repo treats as specs that the default globs miss
  • test_cmd: the suite command, if auto-detection (Taskfile test / go / cargo / npm / pytest) picks the wrong one
  • TYPESAFE_API_KEY (or OPENROUTER_API_KEY) in the env store for the calibrated verdicts
Input Type Default Required Meaning
repo_path string
repo_url string
base_branch string
extra_specs string
exclude string "openspec/changes/archive/**,**/node_modules/**,**/vendor/**,.wfx-*/**,**/README.md,**/INDEX.md,**/template*.md"
max_requirements integer 0
test_cmd string
decisions string
pr_prefix string "[spec-drift]"
dry_run boolean true
isolate boolean true
# Step Kind Skills Gates
1 collect
Collect specs and split into requirements
shell (run:) exitCode = 70 → fail
exitCode = 78 → skip to report
2 map
Map every requirement to code (one mapper per spec file)
agent team (1) repo-navigator
3 coverage
Prove every requirement was mapped (code)
shell (run:) exitCode = 70 → fail
exitCode = 78 → skip to judge
4 map_gaps
Map the requirements nobody mapped
agent repo-navigator
5 judge
Judge every requirement (JEV) and plan
shell (run:) exitCode = 70 → fail
exitCode = 78 → skip to report
6 recommend
Recommend change_code / change_spec / clarify with the smallest edit
agent repo-navigator doc-syncer
7 decide
A person decides every item (change_code / change_spec / skip)
shell (run:) exitCode = 70 → fail
exitCode = 20 → needs_input
exitCode = 78 → skip to report
8 act
Make each decided change (fix-author for code, doc-syncer for specs)
agent fix-author doc-syncer repo-navigator
9 verify
Prove the branch (lanes, suite, re-judge to conforms)
shell (run:) exitCode = 70 → fail
exitCode = 20 → needs_input
10 review
Adversarial review on a different model (change-reviewer)
agent
on gemini
change-reviewer approved = false → needs_input
11 write_pr
Write the PR body (code)
shell (run:) exitCode = 70 → fail
12 claims
Check every change claim against its commit (JEV)
shell (run:) exitCode = 20 → needs_input
exitCode = 70 → fail
13 dry_run_stop
Stop here on a dry run
shell (run:) exitCode = 78 → skip to report
14 publish
Push and open the PR
shell (run:) human approval first
exitCode = 70 → fail
15 report
Report
shell (run:)
  • publish waits for wfx approve <run-id> (or wfx reject <run-id> -m "why") before it runs.
  • decide pauses for input when exitCode is 20: “{{ .Output.stdout }}”. Resume with wfx answer <run-id> -m "...".
  • verify pauses for input when exitCode is 20: “The branch did not prove out — {{ .Output.stdout }} (answer accept-verify to continue anyway; the PR will say so)”. Resume with wfx answer <run-id> -m "...".
  • review pauses for input when approved is false: “The reviewer blocked the branch: {{ .Output.verdict }}”. Resume with wfx answer <run-id> -m "...".
  • claims pauses for input when exitCode is 20: “PR claims not supported by their commits — {{ .Output.stdout }} (answer accept-claims to publish anyway; the body will say so)”. Resume with wfx answer <run-id> -m "...".
  • hand-drawn-diagrams: the run published hand-drawn-diagrams#4, titled “[spec-drift] 1 code fix(es), 2 spec update(s) from 94 checked requirements”, and it was merged (commit 62d8df7: “Proven live: hand-drawn-diagrams PR #4”).
  • citenexus: a run over 698 requirements failed at publish with GitHub’s “Body is too long”. The PR body is now trimmed to fit GitHub’s 65,536-character limit: conforming rows are dropped first, and the full table is kept in pr-body-full.md (commit 4a9520f).