--- phase: 15 slug: ci-skip-api-harness-jobs-for-doc-only-prs status: draft nyquist_compliant: true wave_0_complete: false created: 2026-06-12 --- # Phase 15 — Validation Strategy > Per-phase validation contract for feedback sampling during execution. This phase is CI workflow config + tool config + mechanical markdown fixes. There is no application business logic; the gate-job result logic is validated by static YAML checks plus real CI behavior on doc-only vs code PRs (not a unit-test framework). --- ## Test Infrastructure | Property | Value | |----------|-------| | **Framework** | Static (markdownlint-cli2 + Prettier + `yq`/`grep`) for local checks; Gitea Actions CI (behavioral) for SC-1/2/3 | | **Config file** | `.markdownlint-cli2.jsonc` (new, Plan 01); `.gitea/workflows/ci.yml` (modified, Plans 01/02) | | **Quick run command** | `pnpm md:lint && pnpm format:check` | | **Full suite command** | `pnpm md:lint && pnpm format:check` locally; then a doc-only PR + a code PR observed in Gitea Actions | | **Estimated runtime** | local ~3s; CI doc-only PR ~30s; CI code PR ~5min | --- ## Sampling Rate - **After every task commit:** Run `pnpm md:lint` (Plan 01) or `yq -e '.jobs.' .gitea/workflows/ci.yml` (Plan 02). - **After every plan wave:** Run `pnpm md:lint && pnpm format:check`; for Plan 02, parse ci.yml with `yq` and grep the gate's per-job result checks. - **Before `/gsd-verify-work`:** local checks green; CI behavioral checks observed on throwaway PRs (Plan 03 checkpoint). - **Max feedback latency:** ~3s local; CI behavioral confirmation is the operator checkpoint in Plan 03. --- ## Per-Task Verification Map | Task ID | Plan | Wave | Success Criterion | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status | |---------|------|------|-------------------|------------|-----------------|-----------|-------------------|-------------|--------| | 15-01-01 | 01 | 1 | SC-4 (setup) | T-15-01/02/03 | Pinned devDep; `.planning/**` excluded from lint scope | static | `test -f .markdownlint-cli2.jsonc && node -e "require('./package.json').scripts['md:lint']"` | ❌ W0 (config new) | ⬜ pending | | 15-01-02 | 01 | 1 | SC-4 | T-15-03 | Gate can fail on a real violation; baseline green; no Prettier conflict | static | `pnpm md:lint && pnpm format:check` | ✅ (after fixes) | ⬜ pending | | 15-02-01 | 02 | 2 | SC-1, SC-2 | T-15-05/06 | Positive `code` filter — ambiguous files default to full gate; action pinned @v4 | static | `yq -e '.jobs.changes.outputs.code' ci.yml && grep "needs.changes.outputs.code == 'true'" ci.yml` | ❌ W0 (jobs new) | ⬜ pending | | 15-02-02 | 02 | 2 | SC-1, SC-2, SC-3(YAML) | T-15-04/07 | Gate fails on fast-checks!=success; individual `needs.X.result` (no broken wildcard) | static | `yq -e '.jobs.gate.if == "always()"' ci.yml && grep 'needs.fast-checks.result' ci.yml && ! grep 'needs.\*.result' ci.yml` | ❌ W0 (gate new) | ⬜ pending | | 15-03-01 | 03 | 3 | SC-3 (docs) | T-15-10 | publish.yml comment matches new required checks | static | `grep 'CI / gate' .gitea/workflows/publish.yml` | ✅ (publish.yml exists) | ⬜ pending | | 15-03-02 | 03 | 3 | SC-1, SC-2, SC-3 | T-15-08/09 | Drop api/harness required; require gate; only after `CI / gate` reports | manual (operator) | Gitea branch-protection UI/API + throwaway doc-only & code PRs | Manual | ⬜ pending | *Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky* --- ## Wave 0 Requirements These artifacts do not exist before this phase and are created within it (no separate test scaffold needed — the "tests" are the static checks above): - [ ] `.markdownlint-cli2.jsonc` — new config (Plan 01 Task 1); required before `pnpm md:lint` runs - [ ] root `md:lint` script + `markdownlint-cli2` devDep (Plan 01 Task 1) - [ ] 13 baseline markdown violations fixed (Plan 01 Task 2) — needed for `pnpm md:lint` to pass - [ ] `changes` + `gate` jobs in ci.yml (Plan 02) — needed before any `yq`/grep gate check passes - [ ] Gitea branch-protection update — manual operator step (Plan 03 Task 2), only after `CI / gate` has reported at least once --- ## Manual-Only Verifications | Behavior | Success Criterion | Why Manual | Test Instructions | |----------|-------------------|------------|-------------------| | Branch protection requires `CI / fast-checks` + `CI / gate`, not `CI / api`/`CI / harness` | SC-3 | Gitea admin config — cannot be set in a workflow YAML file (RESEARCH Gitea-Specific Note #4) | Gitea → Settings → Branches → edit `main` rule; set required contexts to exactly `CI / fast-checks` + `CI / gate`; remove `CI / api` + `CI / harness` (Plan 03 Task 2) | | Doc-only PR is mergeable with api/harness skipped | SC-1, SC-3 | Requires a live PR run + the live protection rule | Open a throwaway `*.md`-only PR; confirm api/harness skipped, `CI / gate` passes, PR mergeable | | Code PR runs and gates on all jobs | SC-2 | Requires a live PR run | Open a throwaway `*.ts` PR; confirm fast-checks/api/harness/gate all run; PR mergeable only when green | --- ## Validation Sign-Off - [x] All tasks have ``/static verify or are the designated manual operator checkpoint - [x] Sampling continuity: no 3 consecutive code tasks without automated verify (the only manual task is the unavoidable Gitea-admin checkpoint) - [x] Wave 0 covers all newly-created artifacts - [x] No watch-mode flags - [x] Feedback latency ~3s local - [x] `nyquist_compliant: true` set in frontmatter **Approval:** pending