BOHICA-LABS / BOHICA-LABS/vsdd-factory
enhancement(steady-state): post-SHIPPED PRs to develop bypass every factory quality gate — no spec-drift check, no consistency-validator, no input-hash scan
- Dominant language
- Rust
- Stars
- 2
- Forks
- 1
- Avg merge
- 6h 43m
- Merged PRs (30d)
- 29
Description
## Defect class
Once a VSDD project reaches `SHIPPED` and enters steady-state, PRs to `develop` bypass every factory quality gate that phase-1..7 enforced. `orchestrator/steady-state.md` (referenced in the orchestrator system prompt as a load-on-demand file) exists but is not automatically invoked by any git hook, GitHub Action, or `/vsdd-factory:` skill. `/vsdd-factory:check-input-drift` is phase-gate-only.
Silent-drift class of failure: post-SHIPPED PRs land on `develop`, touch files that ARE (or OUGHT to be) inputs to specs, but no factory step notices. Spec versions freeze at their last-phase-7 values while the codebase drifts underneath.
## Observed failure (switchboard-blue, 2026-07-04)
After `v0.1.0-rc.1 SHIPPED` (Burst 100), two consecutive PRs landed on `develop`:
- **PR #74** — user-facing operator docs (docs/getting-started.md, docs/sbctl.md).
- **PR #75** — Formula rename `switchboard.rb` → `switchboard-a.rb` (alpha channel reservation, sbctl packaging omission).
Both introduced facts that belong in `.factory/specs/`:
- ARCH-06 §Distribution & Packaging (Homebrew alpha channel `switchboard-a`, formula-slot reservation, sbctl packaging plan).
- cicd-setup.md §1 workflow rows (the alpha-publish workflow that runs on tag push).
Neither PR triggered any factory gate. Spec catalog stayed at v1.0. The user, not the factory, caught the drift **two days after PR #75 merged** — only by asking directly during a steady-state operator-doc + spec-drift audit.
## Root cause
Three layers, each with a gap:
1. **Automation gap.** No workflow/hook watches PRs to `develop` post-SHIPPED against `inputDocuments:` frontmatter. `/vsdd-factory:check-input-drift` exists but is a phase-gate skill, not a steady-state trigger.
2. **Documentation gap.** `orchestrator/steady-state.md` describes steady-state at a policy level but has no enforceable gate. No mandatory step ties spec version to changed inputs.
3. **Frontmatter gap.** `inputDocuments:` is stale in every spec that references shipped files. ARCH-06 v1.0 did not list `.github/workflows/ci.yml`; cicd-setup.md v1.0 did not list `Formula/switchboard-a.rb`. The gate would fail-open on incomplete input lists even if the gate existed.
## Failure scenario
Any PR to `develop` after `SHIPPED` that touches a file listed (or that OUGHT to be listed) in some spec's `inputDocuments:` — the spec version stays at 1.0, no changelog row is added, no adversary/consistency-validator sees it. Multi-PR drift compounds silently.
Detected only when:
- A human asks directly.
- The next release cycle's phase-1 adversary catches accumulated drift weeks or months later.
- An operator hits a docs-vs-behavior mismatch.
## Proposed fix (three-part)
### 1. New workflow `.github/workflows/spec-drift.yml`
Auto-generated as part of `phase-1-cicd-setup` for every project so every VSDD-managed repo inherits it. On every PR to `develop`:
- Reads every spec's `inputDocuments:` frontmatter (glob `.factory/specs/**/*.md`).
- Runs `git diff --name-only $BASE..HEAD` and intersects with the union of all `inputDocuments:`.
- Fails with a specific listing of "PR touches file X which is an input to spec Y v1.N; spec Y has not been amended in this PR" if the intersection is non-empty AND the spec itself was not touched by the PR.
- Optional escape hatch: `[skip-spec-drift]` in the PR body for PRs that pre-declare the drift as accepted (with a follow-up story ID).
### 2. Register `steady-state-spec-drift` as a mandatory step
Add to `agents/orchestrator/steady-state.md` a step that runs after every merge to `develop`. The orchestrator picks up the workflow output and either:
- Dispatches spec-steward to amend the affected spec(s) in a follow-up PR.
- Records the intentional deferral in a drift-register with a target release.
### 3. New skill `/vsdd-factory:steady-state-drift-check`
CLI-invokable local check with the same scan logic as (1). Operators can run it before opening a PR to see whether their diff will trigger the gate.
## Acceptance criteria
- [ ] `phase-1-cicd-setup` scaffolds `.github/workflows/spec-drift.yml`
- [ ] `orchestrator/steady-state.md` has a `steady-state-spec-drift` step
- [ ] `/vsdd-factory:steady-state-drift-check` skill registered
- [ ] `docs/FACTORY.md` or `docs/VSDD.md` picks up "spec drift in steady-state" as a first-class concern
- [ ] All template `inputDocuments:` frontmatter examples in the plugin cover CI/CD + packaging files (backfill from switchboard-blue as blueprint)
## Duplicate check
- Not #396 (citation-corpus sweep — operates inside a phase, not steady-state).
- Not #487 (smoke sentinel — operator-boundary regression, not spec-drift).
- Related: #396 (in-phase citation sweep), #487 (smoke gate in delivery loop) — both close different perimeters of the same "we need a gate that catches what we don't know we're missing" pattern.
## Priority
**HIGH** — silent drift accumulation. Every VSDD project reaching SHIPPED will hit this within days of steady-state. switchboard-blue hit it within 48h.
Contributor guide
Assessment
This issue has not been assessed yet.