3 plans across 3 waves: - 15-01: markdownlint-cli2 config/script/step + fix 13 baseline violations (SC-4) - 15-02: ci.yml changes job + conditional api/harness + always-running gate (SC-1/2, SC-3 YAML) - 15-03: operator branch-protection checkpoint + publish.yml comment (SC-3)
88 lines
5.4 KiB
Markdown
88 lines
5.4 KiB
Markdown
---
|
|
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.<job>' .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 `<automated>`/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
|