5.8 KiB
phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | |||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 15-ci-skip-api-harness-jobs-for-doc-only-prs | 02 | ci |
|
|
|
|
|
|
Phase 15 Plan 02: CI doc-only skip + gate aggregate Summary
One-liner: changes job (dorny/paths-filter@v4) classifies each PR; api/harness skip on code==false; always-running gate job aggregates all results using Gitea-safe individual needs.X.result checks, emitting the CI / gate status that Plan 03's branch-protection update requires.
Tasks Completed
| Task | Name | Commit | Files |
|---|---|---|---|
| 1 | Add changes job and gate api/harness on code output | 7260438 |
.gitea/workflows/ci.yml |
| 2 | Add always-running gate aggregate job | 547b12c |
.gitea/workflows/ci.yml |
What Was Built
Task 1 — changes job + conditional api/harness:
A new changes job using dorny/paths-filter@v4 was inserted before fast-checks in .gitea/workflows/ci.yml. It:
- Runs on
ubuntu-latestwithif: github.event_name == 'pull_request' - Declares
permissions: pull-requests: read(job-scoped, required by paths-filter v4) - Emits
outputs.code: ${{ steps.filter.outputs.code }} - Contains a single
uses: dorny/paths-filter@v4step withid: filterand NOactions/checkout - Defines a positive
codefilter covering**/*.ts,**/*.tsx,**/*.js,**/*.json,**/*.yaml,**/*.yml,apps/**,packages/**,pnpm-lock.yaml,Dockerfile,docker-compose*.yml
The api and harness jobs were modified:
- Added
needs: [changes] - Changed
iffromgithub.event_name == 'pull_request'togithub.event_name == 'pull_request' && needs.changes.outputs.code == 'true' - Updated inline comment to say "skipped for doc-only PRs"
- All services, env, and step bodies left unchanged
Task 2 — gate aggregate job:
A new gate job was appended at the end of ci.yml:
runs-on: ubuntu-latestneeds: [fast-checks, changes, api, harness]if: always()— ensures the job reports regardless of upstream outcome- One step running a bash script that:
- Fails (exit 1) if
needs.fast-checks.resultis notsuccess(fast-checks always runs) - Iterates over
needs.api.resultandneeds.harness.result, failing if either is notsuccessorskipped - Echoes "Gate passed." otherwise
- Fails (exit 1) if
- Uses individual
needs.X.resultreferences (notcontains(needs.*.result,...)) due to Gitea 1.26.2 bug #31007
Decisions Made
- D-15-02-CHANGES-JOB: Positive
codefilter chosen (not adocsexclusion filter) so any new or ambiguous file type defaults to the full gate. A doc-only PR must have every changed file fall outside the code patterns. - D-15-02-GATE-INDIVIDUAL: Individual
needs.X.resultchecks used instead ofcontains(needs.*.result, ...)wildcard — Gitea 1.26.2 issue #31007 confirms the wildcard returns false even when jobs succeed. - D-15-02-GATE-ALWAYS:
if: always()on thegatejob prevents deadlock when upstream jobs are skipped. The deadlock bug (Gitea #27906) was fixed in 1.21.8; this instance runs 1.26.2.
Deviations from Plan
None — plan executed exactly as written.
Threat Model Coverage
| Threat | Mitigation | Status |
|---|---|---|
| T-15-04: gate passes when fast-checks fails | gate exits 1 on fast-checks != success; skipped accepted only for api/harness | Implemented |
| T-15-05: code PR misclassified doc-only | positive code filter — any ambiguous file matches code and runs full gate | Implemented |
| T-15-06: supply chain via dorny/paths-filter@v4 | pinned to @v4 tag; pull-requests:read only; no secrets access | Implemented |
| T-15-07: required check deadlock | gate uses if:always(); api/harness NOT added as required checks (Plan 03 scope) | Implemented |
Known Stubs
None — this plan produces only CI workflow YAML. No runtime state or UI involved.
Threat Flags
None — no new network endpoints, auth paths, file access patterns, or schema changes.
Verification
Static (pre-merge):
- Python yaml.safe_load parses ci.yml without error
changesjob present withdorny/paths-filter@v4,id: filter,permissions: pull-requests: read,outputs.code- No
actions/checkoutstep inchangesjob apiandharnesshaveneeds: [changes]and combinedifwithneeds.changes.outputs.code == 'true'gatejob present withif: always()andneeds: [fast-checks, changes, api, harness]needs.fast-checks.result,needs.api.result,needs.harness.resultindividually referenced in gate- No
contains(needs.*.resultwildcard in file
Behavioral (post-merge, per 15-VALIDATION.md):
- Doc-only PR:
changesemitscode=false;api/harnessshow skipped;fast-checksruns;gatepasses - Code PR: all three run;
gatepasses when green - Gate-fail path: failing fast-checks causes
gateto exit 1