diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index b43991b..a688908 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -314,7 +314,7 @@ Plans: | 12. Initial Setup Wizard | v1.1 | 0/? | Not started | - | | 13. Real Lint Gate (ESLint) | v1.1 | 3/3 | Complete | 2026-06-12 | | 14. Desktop E2E Coverage | v1.1 | 1/1 | Complete | 2026-06-12 | -| 15. Doc-Only CI Skip + MD Lint | v1.1 | 3/3 | Complete | 2026-06-12 | +| 15. Doc-Only CI Skip + MD Lint | v1.1 | 3/3 | Complete | 2026-06-12 | ## Backlog diff --git a/.planning/STATE.md b/.planning/STATE.md index d402fae..3af28c3 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,16 +2,16 @@ gsd_state_version: 1.0 milestone: v1.1 milestone_name: Operability & Polish -status: executing +status: completed stopped_at: Phase 14 context gathered -last_updated: "2026-06-12T14:39:49.644Z" -last_activity: 2026-06-12 -- Phase 15 execution started +last_updated: "2026-06-12T15:18:17.057Z" +last_activity: 2026-06-12 progress: total_phases: 18 - completed_phases: 4 + completed_phases: 5 total_plans: 15 - completed_plans: 12 - percent: 22 + completed_plans: 15 + percent: 28 --- # Project State @@ -25,14 +25,15 @@ See: .planning/PROJECT.md (updated 2026-06-10) ## Current Position -Phase: 15 (ci-skip-api-harness-jobs-for-doc-only-prs) — PENDING (deferred checkpoint) -Plan: 15-03 (Task 2 of 2 — human-action checkpoint, deferred) +Phase: 999.1 +Plan: Not started Status: Plans 15-01 + 15-02 complete; 15-03 Task 1 (publish.yml comment) committed (da623ac); 15-03 Task 2 awaiting operator after branch merges to main -Last activity: 2026-06-12 -- Phase 15 code complete; PR pushed; 15-03 operator checkpoint deferred to post-merge +Last activity: 2026-06-12 ### Deferred Checkpoint — Phase 15 Plan 15-03 Task 2 (human-action) Operator must update Gitea branch protection on `main` AFTER this branch merges and `CI / gate` has reported at least once: + - Set required status checks to EXACTLY: `CI / fast-checks` + `CI / gate` - REMOVE: `CI / api` + `CI / harness` (now conditionally skipped on doc-only PRs, gated via the always-running `CI / gate`) - CLI option (login Bergerhouse): `tea api --method PATCH repos/luckberg/familysync/branches/main/protection --data '{"status_check_contexts":["CI / fast-checks","CI / gate"]}'` @@ -46,7 +47,7 @@ Resume: after the operator completes the change, re-run `/gsd-execute-phase 15` **Velocity:** -- Total plans completed: 25 +- Total plans completed: 31 - Average duration: - - Total execution time: 0 hours @@ -59,6 +60,7 @@ Resume: after the operator completes the change, re-run `/gsd-execute-phase 15` | 07 | 4 | - | - | | 13 | 3 | - | - | | 14 | 1 | - | - | +| 15 | 3 | - | - | **Recent Trend:** diff --git a/.planning/phases/15-ci-skip-api-harness-jobs-for-doc-only-prs/15-VERIFICATION.md b/.planning/phases/15-ci-skip-api-harness-jobs-for-doc-only-prs/15-VERIFICATION.md new file mode 100644 index 0000000..e5c8df7 --- /dev/null +++ b/.planning/phases/15-ci-skip-api-harness-jobs-for-doc-only-prs/15-VERIFICATION.md @@ -0,0 +1,103 @@ +--- +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 13–19 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)_