Files
2026-06-18 22:21:38 -04:00

104 lines
7.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 15-ci-skip-api-harness-jobs-for-doc-only-prs
verified: 2026-06-12T00:00:00Z
status: passed
score: 3/3 must-haves verified
overrides_applied: 0
---
# Phase 15: CI doc-only skip + markdown lint gate — Verification Report
**Phase Goal:** Aggregate-gate the slow api/harness CI jobs so doc-only PRs to main merge without running them (no branch-protection deadlock), and add markdownlint to `fast-checks` so docs get a fast format+lint gate.
**Verified:** 2026-06-12
**Status:** passed
**Re-verification:** No — initial verification
## Requirement Traceability Note
No formal REQ-IDs are assigned to this phase (promoted from backlog 999.17 as CI tooling/operability work). Requirement-traceability is N/A; this is noted here rather than flagged as a gap.
---
## Goal Achievement
### Observable Truths (Success Criteria)
| # | Truth | Status | Evidence |
|---|-------|--------|----------|
| SC-1 | A doc-only PR (only docs/\*\*.md or root \*.md) skips `api` and `harness` jobs and is still mergeable — no missing-required-check deadlock | VERIFIED | The `changes` job's `code` filter lists only code paths (`**/*.ts`, `apps/**`, `pnpm-lock.yaml`, `Dockerfile`, `docker-compose*.yml`, etc.) with no `docs/**` or root `*.md` entry. A doc-only PR yields `code=false``api`/`harness` skip. The `gate` job uses `if: always()` and accepts `skipped` as a passing state for api/harness. Branch protection requires `CI / fast-checks (pull_request)` + `CI / gate (pull_request)` only — both always-reporting. Verified live: PR #11 (code PR) ran all five jobs; the protection rule was confirmed via tea API PATCH + re-GET. |
| SC-2 | A code PR runs `fast-checks`, `api`, `harness`, and `gate`, and is mergeable only when all are green | VERIFIED | `api` and `harness` carry `needs: [changes]` and `if: github.event_name == 'pull_request' && needs.changes.outputs.code == 'true'`. Any file matching the positive code filter triggers all heavy jobs. The `gate` job fails (exit 1) if `needs.fast-checks.result != 'success'` or if `needs.api.result` / `needs.harness.result` is neither `success` nor `skipped`. Confirmed live by PR #11 (a code PR) where all five jobs ran and reported success. |
| SC-3 | Branch protection on `main` requires exactly `CI / fast-checks` + `CI / gate` and no longer requires `CI / api`/`CI / harness` | VERIFIED | tea API GET on `repos/luckberg/familysync/branch_protections/main` returns `status_check_contexts: ['CI / fast-checks (pull_request)', 'CI / gate (pull_request)']` with `enable_status_check: true`. `CI / api` and `CI / harness` are absent. Context suffix `(pull_request)` per decision D-15-03-CTX-SUFFIX — Gitea emits suffixed contexts; bare names would deadlock. |
**Score:** 3/3 truths verified
---
### Required Artifacts
| Artifact | Expected | Status | Details |
|----------|----------|--------|---------|
| `.markdownlint-cli2.jsonc` | markdownlint-cli2 config (extends prettier preset; content rules; globs + ignores) | VERIFIED | File exists. `config.extends = "markdownlint/style/prettier"`. MD001/MD024/MD040/MD031/MD051/MD052 enabled; MD041/MD034/MD036 disabled. `globs: ["docs/**/*.md", "*.md", "apps/**/*.md"]`. `ignores: [".planning/**", "node_modules/**", "**/node_modules/**", ".pnpm-store/**"]`. |
| `package.json` | `md:lint` script + `markdownlint-cli2` devDependency | VERIFIED | `scripts["md:lint"] = "markdownlint-cli2"` (no glob args — config-file-driven). `devDependencies["markdownlint-cli2"] = "0.22.1"` (exact pin, no `^`/`~`). |
| `.gitea/workflows/ci.yml` | changes job, md lint step in fast-checks, conditional api/harness, always-running gate | VERIFIED | All four structural elements present (detail in Key Link Verification below). YAML parses without error. |
| `.gitea/workflows/publish.yml` | Updated safety-gate comment naming new required checks | VERIFIED | Comment at lines 1319 names `CI / fast-checks` and `CI / gate`; no longer asserts `CI / api`/`CI / harness` are required. Old "three required checks (…api, …harness)" clause is replaced. YAML parses without error. |
---
### Key Link Verification
| From | To | Via | Status | Details |
|------|----|-----|--------|---------|
| `.gitea/workflows/ci.yml` fast-checks job | `package.json` `md:lint` script | Step "Markdown lint" runs `pnpm md:lint` | WIRED | Step present at position 6 in fast-checks steps, after "Format check" (pos 5) and before "Typecheck" (pos 7). |
| `package.json` `md:lint` script | `.markdownlint-cli2.jsonc` | `markdownlint-cli2` auto-discovers root config | WIRED | Script is bare `markdownlint-cli2` with no CLI glob args; globs/ignores live in the config file. `pnpm md:lint` exits 0 scanning 12 files. |
| `ci.yml` `api`/`harness` jobs | `ci.yml` `changes` job output | `needs: [changes]` + `if: needs.changes.outputs.code == 'true'` | WIRED | Both heavy jobs carry `needs: [changes]` and the combined `if`. Confirmed via YAML parse. |
| `ci.yml` `gate` job | `ci.yml` `fast-checks`/`api`/`harness` results | `needs: [fast-checks, changes, api, harness]` + `if: always()` + individual `needs.X.result` checks | WIRED | `gate.needs` contains all four jobs. `gate.if = "always()"`. Bash script references `needs.fast-checks.result`, `needs.api.result`, `needs.harness.result` individually. No `needs.*.result` wildcard (Gitea bug #31007 avoided). |
| Gitea branch protection (main) | `ci.yml` `gate` job | Required status check `CI / gate (pull_request)` | WIRED | tea API GET confirms `status_check_contexts = ['CI / fast-checks (pull_request)', 'CI / gate (pull_request)']`. `enable_status_check = true`. `CI / api (pull_request)` and `CI / harness (pull_request)` are absent. |
---
### Behavioral Spot-Checks
| Behavior | Command | Result | Status |
|----------|---------|--------|--------|
| `pnpm md:lint` exits 0 on current tree | `pnpm md:lint` | "Summary: 0 error(s)" / exit 0 | PASS |
| 12 in-scope files scanned, `.planning/**` excluded | `pnpm md:lint` output | "Finding: … !.planning/** …; Linting: 12 file(s)" | PASS |
| `ci.yml` parses as valid YAML | `python3 -c "import yaml; yaml.safe_load(...)"` | No error | PASS |
| `publish.yml` parses as valid YAML | `python3 -c "import yaml; yaml.safe_load(...)"` | No error | PASS |
| Branch protection requires exactly fast-checks + gate, no api/harness | `tea api repos/luckberg/familysync/branch_protections/main` | `status_check_contexts: ['CI / fast-checks (pull_request)', 'CI / gate (pull_request)']` | PASS |
| Markdown lint step is between Format check and Typecheck | YAML parse of fast-checks steps | Format check @ idx 5, Markdown lint @ idx 6, Typecheck @ idx 7 | PASS |
| No `needs.*.result` wildcard in gate (Gitea #31007 guard) | `grep 'needs\.\*\.result' ci.yml` | No match | PASS |
| All three individual result refs present in gate | count of `needs.fast-checks.result`, `needs.api.result`, `needs.harness.result` | 3 matches | PASS |
---
### Anti-Patterns Found
| File | Line | Pattern | Severity | Impact |
|------|------|---------|----------|--------|
| — | — | — | — | None found |
No `TBD`, `FIXME`, or `XXX` markers in any file modified by this phase. No stub implementations. No hardcoded empty data. No orphaned artifacts.
---
### Human Verification Required
None. All success criteria are verifiable statically (YAML structure, config values, branch-protection API state) or behaviorally (`pnpm md:lint` exit code, file counts). The one item that was previously a human-action checkpoint (Task 2 of Plan 03 — branch protection update) was executed by the agent under operator authorization and independently confirmed via the tea API GET in this verification session.
---
### Requirements Coverage
Requirement-traceability is N/A for this phase per the phase brief. No formal REQ-IDs are assigned. This is documented here to distinguish it from a missing-coverage gap.
---
### Gaps Summary
None. All three success criteria are verified against live codebase and live admin state.
---
_Verified: 2026-06-12_
_Verifier: Claude (gsd-verifier)_