Skip to main content
Status: active · Added: 2026-06-02 · Origin: HR-44/WENO spec-workflow dogfood This doc defines how an acceptance criterion (AC) or user story becomes verified, and the testing-quality rules that keep “verified” honest. It exists because a dogfood found the spec pipeline could mark a feature shipped while it was unproven — or broken.

1. The problem this fixes

The spec pipeline (create → research → plan → tasks → compliance) is authoring-only: it writes ACs as status: planned, draft: true and nothing ever promotes them. Corpus-wide that left 0 of 4,559 ACs verified. Worse, every Proliant/WENO integration suite skipped by default (describe.skipIf(!hasLocalSupabase)), so a never-executed implementation read as green. “Done” was defined as artifacts exist, not capability proven. Standing up the live stack and running the suites for real (2026-06-02) found three genuine defects behind the green-by-skip — see specs/hr/reviews/HR-44-DOGFOOD-FINDINGS-2026-06-02.md.
A test declares the AC/US it proves with a JSDoc tag in its source:
scripts/specs/verify-acs.mjs (npm spec:verify-acs) finds those backlinks, runs exactly the backing tests, and promotes an item to verified only when they actually pass:
Promotion rule (strict): ≥1 backing file AND, across them, passed > 0 AND failed == 0 AND skipped == 0. A skip is not a pass.
  • ACs (frontmatter): status: planned, draft: truestatus: verified, draft: false + verified_by: [tests], verified_at.
  • User stories (- **US-N** [planned] … body items): [planned][verified].
Commands:
The terminal AC state verified was added to ListItemStatus (scripts/specs/schema/types.ts); it is distinct from done (implemented) — code can ship done while no test proves the AC.

Verifying integration-only ACs

Some ACs are only provable by an integration test that needs a served stack. The gate counts what actually passes in the current environment — run it with the live stack up (see §4). Such ACs verify for real; an AC whose only proof is a skip stays planned. Don’t backlink an AC to a test that can’t pass unattended unless you accept it will only verify on a stack-equipped runner (incl. CI with the stack).

3. Skip-reason taxonomy — stop green-by-skip

Every intentional skip must declare why, via tests/utils/skip-reasons.ts: Example — the F3 employee-sync bug is parked honestly, not hidden:
scripts/testing/scan-skip-reasons.mjs (npm test:skip-scan) reports skips by category and, with --enforce, fails when any CAPABILITY_ABSENT or UNCLASSIFIED skip exists — so capability gaps are tracked and every skip must say why.

4. Running the live verification substrate

Integration tests need the local stack and served edge functions. On the DGX box the stack is the encoreos Docker project (REST 54321, DB 54322). .env.local already carries SUPABASE_SERVICE_ROLE_KEY + SUPABASE_URL, so the harness goes live automatically. For Proliant, the edge functions must be served with the fixture-transport flag:
Then npm run test:integration -- tests/integration/hr/proliant/ runs for real.

5. Quality rules (carry forward)

  1. A unit test that asserts a mapper’s output is not proof the row inserts. F3 shipped because employee-mapper.test.ts asserted a flat {first_name,…} shape the hr_employees table rejects. Assert against the real schema (an integration insert), or label the unit test as logic-only.
  2. An integration suite that skips by default is not coverage. It must either run in CI (served stack) or its ACs stay planned. Never let skipIf masquerade as green.
  3. System/cron paths must be tested under the service-role identity. F2 (triggered_by: 'service-role' → uuid 500) only appears when the function is invoked as the service role — exactly how cron and integration tests call it.
  4. Teardown is test code too. F1 (cleanup referencing a non-existent column) was invisible because the suite never reached teardown. Run teardown live.
  5. verified requires a passing test, full stop. --enforce in CI makes a regression (a verified AC whose test breaks or starts skipping) fail the build.