138 lines
6.5 KiB
Markdown
138 lines
6.5 KiB
Markdown
---
|
|
created: 2026-09-15
|
|
status: done
|
|
requirements:
|
|
- REQ-CI-PR-DOCS-002
|
|
- REQ-CI-PR-DOCS-003
|
|
- REQ-CI-PR-DOCS-004
|
|
- REQ-CI-PR-SIZE-001
|
|
system_design:
|
|
- ../../specs/ci/system-design/pull-request-documentation-coverage.md
|
|
- ../../specs/ci/system-design/pull-request-size-labels.md
|
|
legacy_specs: []
|
|
---
|
|
|
|
# Implementation plan: GitHub API resilience
|
|
|
|
## Overview
|
|
|
|
Reduce avoidable GitHub API traffic and recover correctly when GitHub applies a
|
|
transient or secondary rate limit. Two documentation-coverage runs failed with
|
|
HTTP 429 while evaluating otherwise valid pull requests. Read-only replay showed
|
|
about 14 requests for the smaller example and 33 for the larger example,
|
|
including status publication. Per-requirement code searches and repeated pull
|
|
request reads account for much of the avoidable traffic.
|
|
|
|
The CI system owns this package because it owns the trusted workflow event,
|
|
request, mutation, and failure contracts.
|
|
|
|
## Scope
|
|
|
|
In scope: rate-aware retries and diagnostics in the custom documentation
|
|
evaluator. The package also covers request reuse, event gates, and lazy
|
|
size-label definition creation.
|
|
|
|
Out of scope: replacing `GITHUB_TOKEN`, changing documentation policy, or
|
|
changing size rules. The package does not change merge-queue membership or
|
|
repository rulesets. It does not include low-frequency workflow cleanup.
|
|
|
|
## Technical approach
|
|
|
|
Extend the documentation evaluator's existing bounded client instead of adding
|
|
a second request library. Classify errors before each retry. Follow GitHub wait
|
|
headers. Use the documented one-minute minimum for a secondary limit without a
|
|
usable header. Stop within a fixed total wait budget. Emit sanitized diagnostics
|
|
to the runner log.
|
|
|
|
Pass the wrapper's initial pull request snapshot into the evaluator. Build a
|
|
per-snapshot requirement cache from changed exact-head documents and their base
|
|
versions before using code search. Keep code search as the bounded fallback for
|
|
new, moved, unresolved, and ambiguous identities.
|
|
|
|
Narrow documentation coverage to events that can change its inputs. Keep
|
|
`labeled` and `unlabeled` triggers for GitHub routing, use a job-level gate for
|
|
the exact `no-docs-allow` label, and admit `edited` only for base-branch
|
|
retargets. Exclude title and description edits and ready-for-review changes.
|
|
|
|
For size labels, list current pull request labels once and optimistically apply
|
|
the target. Create only the target definition after a narrowly recognized
|
|
missing-label response. Existing target labels require no repository
|
|
label-definition requests.
|
|
|
|
Open PR #3693 is implementation input for Task 01. Reuse its bounded client and
|
|
diagnostic tests after rebasing. Replace its 250/500 ms no-header fallback with
|
|
the documented 60/120 second waits and total budget.
|
|
|
|
## Tests
|
|
|
|
| Criteria | Evidence |
|
|
| --- | --- |
|
|
| AC-CI-PR-DOCS-003.6 through .7 | Client fixtures for transport, 408, 429, rate-limit 403, 5xx, headers, no-header 60/120 second waits, exhaustion, permanent errors, wait-budget overflow, and sanitized logs. |
|
|
| AC-CI-PR-DOCS-004.1 through .3 | Exact-head/base fixtures count calls, reuse the initial snapshot, skip search for verified changed requirements, and retain new-ID, missing-ID, and duplicate-ID failures. |
|
|
| AC-CI-PR-DOCS-004.4 | Workflow contract verifies the minimal event list and exact override-label job gate. |
|
|
| AC-CI-PR-SIZE-001.5, .6, .9, .10 | Workflow contract verifies one current-label read, direct target apply, lazy target creation, concurrent creation recovery, and no definition preflight on the steady path. |
|
|
|
|
Use fixtures from the two failed run shapes. One fixture has four requirement
|
|
IDs in one changed document. The other has eleven IDs in several changed
|
|
documents. Assert request classes and cache keys. Do not use live pull request
|
|
numbers or mutable GitHub state.
|
|
|
|
## End-to-end evidence
|
|
|
|
No application UI changes. Local evidence comes from mocked GitHub responses and
|
|
workflow contract tests. After deployment, manually dispatch coverage for a
|
|
covered pull request and an uncovered pull request. Exercise the override label
|
|
once. Record retry diagnostics for any real throttle. Compare request counts
|
|
with the pre-change 14- and 33-request replays. Do not intentionally cause live
|
|
rate limiting.
|
|
|
|
## Work orders
|
|
|
|
- [x] [Task 01: Add rate-aware API recovery](task-01-rate-aware-api-recovery.md)
|
|
- [x] [Task 02: Consolidate documentation API reads](task-02-consolidate-documentation-api-reads.md)
|
|
- [x] [Task 03: Remove size-label definition preflights](task-03-remove-size-label-definition-preflights.md)
|
|
|
|
Execute sequentially. No subagents are authorized.
|
|
|
|
## Verification
|
|
|
|
Run the exact commands in each work order. After all tasks:
|
|
|
|
```bash
|
|
node --test .github/scripts/pr-docs.test.cjs
|
|
python3 .github/scripts/pr-docs-workflow-contract_test.py
|
|
python3 .github/scripts/pr-size-label-workflow-contract_test.py
|
|
python3 .github/scripts/lint-action-pinning_test.py
|
|
python3 .github/scripts/lint-action-pinning.py
|
|
python3 scripts/list-docs.py validate
|
|
python3 scripts/lint-spec-files.test.py
|
|
python3 scripts/lint-spec-files.py --all
|
|
zizmor .github/workflows/pr-docs.yml
|
|
zizmor .github/workflows/pr-size-label.yml
|
|
git diff --check
|
|
```
|
|
|
|
## Risks
|
|
|
|
- Retrying a status write after an uncertain response can create a duplicate
|
|
status record with the same context and state.
|
|
- A conservative secondary-limit delay consumes runner time. The 180-second
|
|
sleep budget keeps the workflow inside its ten-minute timeout.
|
|
- Exact-head requirement optimization relies on the trusted base catalog's
|
|
unique-ID validation and must scan every changed requirement document in the
|
|
referenced directory.
|
|
- Missing-label errors must be identified narrowly so validation and permission
|
|
failures do not create labels.
|
|
- Label-event gating must preserve merge-group and manual-dispatch paths.
|
|
|
|
## References
|
|
|
|
- [Documentation coverage requirements](../../specs/ci/requirements/pull-request-documentation-coverage.md)
|
|
- [Documentation coverage design](../../specs/ci/system-design/pull-request-documentation-coverage.md)
|
|
- [Pull request size requirements](../../specs/ci/requirements/pull-request-size-labels.md)
|
|
- [Pull request size design](../../specs/ci/system-design/pull-request-size-labels.md)
|
|
- [Documentation coverage decision](../../decisions/2026-09-10-pr-documentation-coverage.md)
|
|
- [GitHub REST API rate limits](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api)
|
|
- [GitHub REST API best practices](https://docs.github.com/rest/guides/best-practices-for-integrators)
|
|
- [Open retry implementation PR #3693](https://github.com/kdlbs/kandev/pull/3693)
|