11 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260611-ozt | 01 | execute | 1 |
|
true |
|
|
Purpose: ci.yml's on: includes pull_request, so Gitea registers an orphaned CI / publish (pull_request) commit status that sits pending forever on every PR (skipped jobs never resolve their status in Gitea Actions). A push-only publish.yml stops the orphan from ever being created. Motivated by phase-8 review finding WR-01 and the new branch-protection rule on main (direct/force push blocked; required checks = the three PR jobs).
Output: .gitea/workflows/publish.yml (new), edited .gitea/workflows/ci.yml, README "Publishing / Releases" section.
<execution_context> @$HOME/.claude/gsd-core/workflows/execute-plan.md @$HOME/.claude/gsd-core/templates/summary.md </execution_context>
@.planning/STATE.md @.gitea/workflows/ci.yml @README.md Task 1: Create publish.yml and strip publish from ci.yml .gitea/workflows/publish.yml, .gitea/workflows/ci.yml Create `.gitea/workflows/publish.yml` as a standalone push-only workflow: - `name: Publish` - Trigger: `on: push: branches: [main]` ONLY. Do NOT carry over the `if: github.event_name == 'push' && github.ref == 'refs/heads/main'` guard from the old job — the push-to-main trigger alone fully replaces it (redundant guard). - Workflow-level `env: MILESTONE: v1.1` (this env is publish-only and moves to this file). - A single job `publish` with `runs-on: ubuntu-latest` (ubuntu-latest is mandatory per D-PROBE-01 — the runner has no self-hosted label). Move the job's four real steps VERBATIM from the current ci.yml publish job (ci.yml lines 318-362): `actions/checkout@v4`; `Compute image tags` (id: tags); `Docker login` (PAT piped via `--password-stdin` from `secrets.REGISTRY_PAT`, username `luckberg`, registry `git.bergerhouse.net`); `Build and push` (docker build `--target production -f apps/api/Dockerfile` from repo root `.`, two `-t` tags, two `docker push`); `Docker logout` with `if: always()`. - Preserve EVERY existing inline comment on those steps verbatim — they encode load-bearing rationale: PAT-via-stdin security (Pitfall 13), REGISTRY_PAT naming because Gitea reserves the GITEA_ prefix (D-PAT-NAMING), build-from-repo-root for the pnpm workspace manifest+lockfile (T-08-10), and the D-04 two-tag scheme (:latest moving + :- immutable). The Compute-image-tags comment references "the workflow-level env var (set to v1.1 above)" — keep that accurate since MILESTONE now lives at the top of THIS file. - Add a header comment block (see Task 2 — same content as the README section, condensed) at the very top of publish.yml above `name: Publish`.Then edit .gitea/workflows/ci.yml:
- Remove the entire
publish:job (current lines 314-362). - Remove the
push:trigger key fromon:(lines 6-7), leaving onlypull_request: branches: [main]. - Remove the workflow-level
env: MILESTONE: v1.1block (lines 9-10) — it was referenced ONLY by the publish job (confirmed: grep ci.yml for MILESTONE returns only the publish Compute-image-tags step). Do not leave an emptyenv:key. - Do NOT rename
name: CIor the job idsfast-checks/api/harness, and do NOT remove theirif: github.event_name == 'pull_request'guards — renaming or removing would change/break the required status contexts (CI / fast-checks (pull_request),CI / api (pull_request),CI / harness (pull_request)). The guards are harmless now thatpush:is gone; leave them. test -f .gitea/workflows/publish.yml && grep -q 'name: Publish' .gitea/workflows/publish.yml && grep -q 'secrets.REGISTRY_PAT' .gitea/workflows/publish.yml && grep -q '--password-stdin' .gitea/workflows/publish.yml && grep -q 'MILESTONE: v1.1' .gitea/workflows/publish.yml && grep -Eq '^\spush:' .gitea/workflows/publish.yml && ! grep -q "github.event_name == 'push'" .gitea/workflows/publish.yml && ! grep -q 'publish:' .gitea/workflows/ci.yml && ! grep -q 'MILESTONE' .gitea/workflows/ci.yml && ! grep -Eq '^\spush:' .gitea/workflows/ci.yml && grep -q 'pull_request:' .gitea/workflows/ci.yml && grep -q 'name: CI' .gitea/workflows/ci.yml && grep -c 'if:' .gitea/workflows/ci.yml | grep -qE '^[3-9]' publish.yml exists with name=Publish, push-to-main-only trigger, no redundant if-guard, workflow-level MILESTONE, the four publish steps with all inline comments intact, and a header doc block. ci.yml has no publish job, no push trigger, no MILESTONE env, retains name=CI and all three PR jobs with their guards.
Then write the SAME information condensed into the header comment block at the top of publish.yml (the block referenced in Task 1) — short bullet lines covering: trigger (push to main / PR merge), the two tags + image, the REGISTRY_PAT secret + naming reason, the branch-protection safety gate / why no test needs:, and the MILESTONE-bump instruction.
Finally verify both workflow YAML files are well-formed. No yamllint/act/js-yaml/pyyaml is available locally (confirmed during planning: no YAML parser in any node_modules, no pyyaml, no ruby yaml). Docker IS available, so parse both files strictly with the purpose-built yq image (no network beyond the image pull, no repo deps):
docker run --rm -i mikefarah/yq:4 e '.' - < .gitea/workflows/publish.yml and likewise for ci.yml — a malformed file makes yq exit non-zero. If the yq image cannot be pulled (offline), fall back to structural inspection: re-read both files end-to-end, confirm consistent 2-space indentation, that every run: | block body is indented under its key, that the moved publish steps parse as a list under jobs.publish.steps, and explicitly NOTE in the SUMMARY that YAML was verified by inspection only (no parser available).
grep -qi 'Publishing|Releases' README.md && grep -q 'REGISTRY_PAT' README.md && grep -q 'familysync-api' README.md && grep -q 'MILESTONE' README.md && grep -q 'branch protection' README.md && grep -qi 'REGISTRY_PAT' .gitea/workflows/publish.yml && (docker run --rm -i mikefarah/yq:4 e '.' - < .gitea/workflows/publish.yml >/dev/null 2>&1 && docker run --rm -i mikefarah/yq:4 e '.' - < .gitea/workflows/ci.yml >/dev/null 2>&1 || echo 'YAML-PARSER-UNAVAILABLE-INSPECTED-MANUALLY')
README has a Publishing/Releases section covering all six points (auto-on-push-to-main, image+two-tags, REGISTRY_PAT secret + naming, branch-protection safety gate, no test needs:, MILESTONE bump). publish.yml header block carries the condensed same. Both YAML files parse cleanly under yq (or are noted as inspected-only if no parser pulled).
<success_criteria>
- A PR to
mainproduces onlyCI / fast-checks,CI / api,CI / harnessstatuses — noCI / publishorphan. - A merge to
maintriggers thePublishworkflow, building/pushingfamilysync-api:latest+familysync-api:v1.1-<shortsha>. - No behavior change to the three PR jobs; required checks still satisfiable.
- Release process is discoverable in README and in the publish.yml header. </success_criteria>