-
Notifications
You must be signed in to change notification settings - Fork 0
287 lines (276 loc) · 12.5 KB
/
Copy pathci.yml
File metadata and controls
287 lines (276 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
name: CI
on:
push:
branches: ["**"]
pull_request:
branches: ["**"]
schedule:
# Run snapshot validation daily at 2 AM UTC to detect regressions
# in real-world repository state, even when no code changes occur.
- cron: '0 2 * * *'
jobs:
lint:
name: Lint (ruff)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install ruff
# Install the repo's own pinned toolchain rather than `ruff>=0.5`. A lint
# gate has to run the version the config was written against: `[tool.ruff]`
# here selects a deliberate rule set (BLE001 and S110 are explicitly
# DROPPED as too noisy, per the comment in pyproject), and a newer ruff
# re-enables rules that config never opted into. `ruff>=0.5` floated up to
# 0.16.1 and this job went from clean to 1996 errors — every one of them
# phantom — red-failing CI on main daily from ~2026-07-29. Taking the pin
# from [project.optional-dependencies].dev keeps one source of truth; do
# not reintroduce a version literal here.
run: pip install -e ".[dev]"
- name: Run ruff
run: ruff check .
typecheck:
name: Type check (ty)
runs-on: ubuntu-latest
# Was advisory (continue-on-error) while 21 pre-existing diagnostics
# were unresolved. Cleared on 2026-05-07 — now blocking.
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install -e .[dev]
- name: Run ty
run: ty check src/
custodian:
name: Custodian doctor
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install -e .[dev]
- name: Verify .custodian.yaml is well-formed
run: custodian-doctor --strict --repo .
license-check:
name: License headers
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check SPDX headers
run: |
missing=$(git ls-files "*.py" | xargs grep -L "SPDX-License-Identifier" 2>/dev/null || true)
if [ -n "$missing" ]; then
echo "Missing SPDX-License-Identifier header in:"
echo "$missing"
exit 1
fi
test:
name: Test (pytest)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install -e .[dev]
- name: Run unit tests excluding slow (PR validation)
if: github.event_name == 'pull_request'
# Unit suite only — integration tests under tests/integration/ need
# live external services (SwitchBoard, Plane, Archon) and run on
# demand, not in CI. PRs exclude slow tests for quick validation.
# Coverage threshold of 85% is the design target from Stage 0.
# CI will fail until coverage improves to meet this target.
# -p no:flaky-detection — the pytest11 entry point imports the whole
# observer package at pytest startup, BEFORE coverage instrumentation,
# marking every module-level line uncovered. The plugin is opt-in by
# design; coverage jobs don't need it loaded.
run: pytest -q tests/unit -m "not slow" -p no:flaky-detection --cov=src --cov-report=html --cov-report=xml --cov-report=term-missing --cov-fail-under=85
- name: Run full unit test suite including slow (main/merge)
if: github.event_name == 'push'
# Unit suite only — integration tests under tests/integration/ need
# live external services (SwitchBoard, Plane, Archon) and run on
# demand, not in CI. Pushes run full suite including slow tests.
# Coverage threshold of 85% is the design target from Stage 0.
# CI will fail until coverage improves to meet this target.
# -p no:flaky-detection — see PR-validation step above.
run: pytest -q tests/unit -p no:flaky-detection --cov=src --cov-report=html --cov-report=xml --cov-report=term-missing --cov-fail-under=85
- name: Upload coverage to Codecov
if: always()
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload coverage reports as artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-reports-${{ github.event_name }}
path: |
coverage_html_report/
coverage.xml
retention-days: 30
reviewer:
name: Reviewer state-machine tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install -e .[dev]
- name: Run pr_review_watcher tests
# The reviewer self-review / verdict-gate / Self-Heal Ladder state machine
# lives at tests/test_pr_review_watcher.py (repo ROOT, not tests/unit), so
# the main "Test (pytest)" job — which runs `pytest tests/unit` — never
# exercised it. This dedicated job gates the governance + self-heal code
# (the #313 regression class: never merge over a CONCERNS verdict; resolve
# concerns instead of conceding) on every PR. Standalone, no live services.
# Isolated from tests/unit so it cannot perturb the doc-accuracy suite's
# collection-count assertions.
run: pytest -q tests/test_pr_review_watcher.py -p no:flaky-detection
reviewer-integration:
name: Reviewer integration tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install -e .[dev]
- name: Run reviewer integration tests
# tests/integration/reviewer exercises the verdict-consolidation +
# merge-decision state machine (happy path, CI-green gate, verdict
# override, timeout recovery, safety paths, instrumentation) end-to-end
# through pr_review_watcher._phase1. Despite living under tests/integration/,
# these are HERMETIC: the GitHub and Plane clients are fully mocked
# (tests/verdicts/conftest.py), so there are NO live services and NO
# network — they run in <1s. The blanket "integration/ needs live services,
# run on demand" policy that excludes the rest of tests/integration/ from CI
# let this suite DRIFT against the evolving self-merge gates (e.g. the
# require_branch_protection fail-closed gate added in #388). This dedicated
# job runs them on every PR so they cannot rot again.
# -p no:flaky-detection — see the "Test (pytest)" job (plugin is opt-in;
# its pytest11 entry point imports the observer package before coverage
# instrumentation). Isolated from tests/unit so it cannot perturb the
# doc-accuracy suite's collection-count assertions.
run: pytest -q tests/integration/reviewer -p no:flaky-detection
performance:
name: Performance regression tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install -e .[dev]
- name: Run performance regression tests
# Dedicated job surfaces timing-bound failures as a labelled CI check.
# All bounds are <50ms per scenario; actual measurements are ~0.1–0.2ms.
# A failure here means collection time regressed by >250x vs baseline.
run: pytest -q tests/unit -m "perf" --no-header -rN
snapshot:
name: Snapshot validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install -e .[dev]
- name: Run snapshot validation tests (PR — quick, excluding slow)
if: github.event_name == 'pull_request'
# Snapshot validation uses 5-layer architecture:
# Layer 1: Schema validation (JSON ↔ Pydantic model roundtrip)
# Layer 2: Completeness validation (required signals present, min 3 non-unavailable)
# Layer 3: Consistency validation (cross-signal semantic checks)
# Layer 4: Real-world accuracy validation (snapshot vs. live tools — marked slow)
# Layer 5: Regression detection (baseline comparison — marked slow)
#
# PR runs exclude slow tests for quick feedback.
# All validation checks must pass; structural failures trigger job failure.
# Transient failures (network, timeouts) are retried up to 3 times.
run: pytest -q tests/integration/observer -m "integration and not slow" --no-header -rN
- name: Run snapshot validation tests (push — full, including slow)
if: github.event_name == 'push'
# Full validation including real-world accuracy (Layer 4) and regression detection (Layer 5).
# These layers test against actual repository state and may take longer.
run: pytest -q tests/integration/observer -m "integration" --no-header -rN
- name: Run snapshot validation tests (scheduled — full, including slow)
if: github.event_name == 'schedule'
# Scheduled runs execute comprehensive validation without time constraints.
# Full validation detects regressions in repository state snapshots,
# even when no new code changes occur. Failures trigger immediate alerts.
run: pytest -q tests/integration/observer -m "integration" --no-header -rN
- name: Upload snapshot validation reports
if: always()
uses: actions/upload-artifact@v4
with:
name: snapshot-validation-reports-${{ github.event_name }}
path: |
tests/integration/observer/validation_reports/
retention-days: 30
strategy:
fail-fast: true
flaky-test-detection:
name: Flaky test detection
runs-on: ubuntu-latest
if: github.event_name == 'push' # Run on merges (not PRs) to detect trends
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: pip install -e .[dev]
- name: Run unit tests with flaky detection
# Runs all unit tests with flaky detection plugin enabled.
# Captures test outcomes, analyzes patterns, and saves metrics.
# This provides baseline data for historical trend detection.
run: pytest -q tests/unit --flaky-detection --flaky-storage=.flaky-tests -v --tb=short
- name: Aggregate flakiness history
if: always()
# Aggregates session reports from past 7 days into daily summaries.
# Computes failure rates, trends, and generates recommendations.
# Output: .flaky-tests/aggregations/YYYY-MM-DD-aggregation.json
run: |
python -c "
from pathlib import Path
from operations_center.observer import FlakyTestStorageManager, FlakyTestAggregator, FlakyTestAlertManager
storage = FlakyTestStorageManager.create_local('.flaky-tests')
agg = FlakyTestAggregator(storage)
report = agg.aggregate(days=7)
storage.save_aggregation(report)
alerts = FlakyTestAlertManager.check_alerts(report)
print('Aggregation complete: ' + str(report.flaky_test_count) + ' flaky tests')
for alert in alerts:
print(' [' + alert.severity.value.upper() + '] ' + alert.alert_type + ': ' + alert.description)
"
- name: Upload flaky test metrics
if: always()
uses: actions/upload-artifact@v4
with:
name: flaky-test-metrics-${{ github.run_id }}
path: |
.flaky-tests/runs/
.flaky-tests/aggregations/
retention-days: 90
- name: Report aggregation status
if: always()
run: |
echo "Flaky test aggregation completed"
ls -la .flaky-tests/aggregations/ 2>/dev/null || echo "No aggregation files created"
strategy:
fail-fast: false