-
Notifications
You must be signed in to change notification settings - Fork 0
390 lines (375 loc) · 16.4 KB
/
Copy pathci.yml
File metadata and controls
390 lines (375 loc) · 16.4 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
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
# merge_group: main'de merge queue rule'u aktif (Alperen, 2026-08-04). Kuyruk, required
# check'leri PR branch'inde değil final merge result üzerinde yeniden koşar; bu event
# dinlenmezse kuyruk check sonucu alamaz ve hiçbir PR merge olamaz.
merge_group:
# Option E / Hole 3.2 (owner-approved 2026-08-12): for a push to main every run
# shared the group `ci-refs/heads/main`, so back-to-back merges cancelled the
# previous main run mid-flight — under an active merge queue, main-push shard
# results were systematically destroyed before they concluded. Main pushes now
# get a per-SHA group (no mutual cancellation); PR/queue refs keep the stale-run
# cancellation that saves compute there.
concurrency:
group: ci-${{ github.ref }}${{ github.ref == 'refs/heads/main' && format('-{0}', github.sha) || '' }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
lockfile-sync:
name: Lockfile Sync Guard
# 535: the merge queue re-runs required checks on the final merge result —
# for this workflow that is Type Check alone. Every other job re-running in
# the queue added ~30min wall-clock per train with no admission value
# (main-push still runs the full matrix).
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
# Root cause of the months-long CI outage: package-lock.json drifted from
# package.json, so every job's `npm ci` failed with a cryptic EUSAGE error.
# This guard runs FIRST and FAST, turning that failure into an actionable
# message before the heavy test matrix ever spins up. `npm ci` itself still
# enforces the lock downstream — this just surfaces drift early and clearly.
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24.x'
cache: npm
- name: Verify package-lock.json is in sync with package.json
run: |
npm install --package-lock-only --ignore-scripts
if ! git diff --quiet -- package-lock.json; then
echo "::error file=package-lock.json::package-lock.json is out of sync with package.json. Run 'npm install' locally and commit the regenerated package-lock.json."
echo "--- drift (package-lock.json) ---"
git --no-pager diff --stat -- package-lock.json
exit 1
fi
echo "package-lock.json is in sync with package.json."
typecheck:
name: Type Check
runs-on: ubuntu-latest
steps:
# fetch-depth: 0 — this job runs lint:gates → lint-master-plan, whose trust-anchor
# resolution is history-sensitive; a shallow clone is now a fail-closed finding
# (xverify-E: depth-1 previously degraded to a WARN pass on this leg).
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '24.x'
cache: npm
- run: npm ci
- run: npm run ci:rebuild-native
- name: Install dashboard dependencies
run: npm ci --prefix src/dashboard --ignore-scripts
- run: npm run lint
- name: MCP Instructions lint (tool count drift guard)
run: node scripts/lint-mcp-instructions.mjs
security:
name: Security Audit
# 535: the merge queue re-runs required checks on the final merge result —
# for this workflow that is Type Check alone. Every other job re-running in
# the queue added ~30min wall-clock per train with no admission value
# (main-push still runs the full matrix).
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24.x'
cache: npm
- run: npm ci
- run: npm run ci:rebuild-native
- name: Dependency audit (fail-closed, signed-exception allowlist; SEC-05)
run: node scripts/check-dependency-audit.mjs
test-core:
name: Tests — Core + Agents
# 535: the merge queue re-runs required checks on the final merge result —
# for this workflow that is Type Check alone. Every other job re-running in
# the queue added ~30min wall-clock per train with no admission value
# (main-push still runs the full matrix).
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
needs: typecheck
strategy:
matrix:
# Node 18/20/22 dropped — all EOL by May 2026:
# - v18 EOL Apr 2025 (1+ year dead)
# - v20 (Iron) Maintenance EOL Mar 2026
# - v22 (Jod) Maintenance EOL May 2026 (this month)
# Active LTS = v24 (Krypton, until May 2027). v26 = Current.
# better-sqlite3 v12.10.0 prebuilds: v24 + v26 (v20/v23 removed).
node-version: [24.x, 26.x]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: npm run ci:rebuild-native
- name: Run core tests
run: npx vitest run tests/core/ tests/agents/
timeout-minutes: 5
test-orchestra:
name: Tests — Orchestra
# 535: the merge queue re-runs required checks on the final merge result —
# for this workflow that is Type Check alone. Every other job re-running in
# the queue added ~30min wall-clock per train with no admission value
# (main-push still runs the full matrix).
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
needs: typecheck
strategy:
matrix:
node-version: [24.x, 26.x]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: npm run ci:rebuild-native
- name: Build dist (real-binary tests need dist/cli/entry.js)
run: |
npx tsc
node scripts/copy-assets.mjs
- name: Run orchestra tests
# Orchestra suite is large (~118 test files) — historical OOM on default
# 2GB heap. Bumped to 8GB + forks pool (isolated workers, no shared state).
# See Sprint 141 CI fix: pre-existing Sprint 139 regression.
env:
NODE_OPTIONS: '--max-old-space-size=8192'
run: npx vitest run tests/orchestra/ --pool=forks
timeout-minutes: 10
test-cli:
name: Tests — CLI
# 535: the merge queue re-runs required checks on the final merge result —
# for this workflow that is Type Check alone. Every other job re-running in
# the queue added ~30min wall-clock per train with no admission value
# (main-push still runs the full matrix).
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
needs: typecheck
strategy:
matrix:
node-version: [24.x, 26.x]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: npm run ci:rebuild-native
- name: Build dist (real-binary tests need dist/cli/entry.js)
run: |
npx tsc
node scripts/copy-assets.mjs
- name: Run CLI tests
run: npx vitest run tests/cli/
timeout-minutes: 10
test-remaining:
name: Tests — MCP + API + Integration + Security + Providers + Monitor + Skills + Analytics
# 535: the merge queue re-runs required checks on the final merge result —
# for this workflow that is Type Check alone. Every other job re-running in
# the queue added ~30min wall-clock per train with no admission value
# (main-push still runs the full matrix).
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
needs: typecheck
strategy:
matrix:
node-version: [24.x, 26.x]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: npm run ci:rebuild-native
- name: Run remaining tests
run: npx vitest run tests/mcp/ tests/api/ tests/integration/ tests/security/ tests/providers/ tests/monitor/ tests/skills/ tests/analytics/ tests/github/
timeout-minutes: 10
test-docs-scripts:
name: Tests — Docs + Scripts (isolated)
# 535: the merge queue re-runs required checks on the final merge result —
# for this workflow that is Type Check alone. Every other job re-running in
# the queue added ~30min wall-clock per train with no admission value
# (main-push still runs the full matrix).
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
needs: typecheck
# Vitest worker timeout (onTaskUpdate) is a known flaky issue in CI.
# Tests pass (508/508) but vitest exits with code 1 due to worker crash.
# Coverage job runs these same tests — this job is supplementary.
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24.x'
cache: npm
- run: npm ci
- run: npm run ci:rebuild-native
- name: Run docs and scripts tests
# 523-004 (flake RCA + sol cross-review): the shard-scoped canary env
# (vitest.config.ts) serializes THIS step and drops it to the dot
# reporter, targeting the onTaskUpdate flake this job's
# continue-on-error exists for. No retry — the RCA rejected bounded
# retry as a fix. continue-on-error above stays on until the RCA's
# acceptance series is met; see task 523-004's .result notes for the
# green-run count so far.
env:
VITEST_DOCS_SCRIPTS_SERIAL: '1'
run: npx vitest run tests/docs/ tests/scripts/ --pool=forks
# 522 (CI-DOCS-SCRIPTS-STEP-TIMEOUT-001): the suite measured 307.86s on a
# saturated runner and the old 5-minute cap SIGKILLed it mid-flight
# (run 31050457808) — same slow-runner class as the 519 test-level raise,
# one layer up. 15 minutes = ~3x measured headroom (519 pattern).
timeout-minutes: 15
test-dashboard:
name: Tests — Dashboard
# 535: the merge queue re-runs required checks on the final merge result —
# for this workflow that is Type Check alone. Every other job re-running in
# the queue added ~30min wall-clock per train with no admission value
# (main-push still runs the full matrix).
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
needs: typecheck
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24.x'
cache: npm
- run: npm ci
- run: npm run ci:rebuild-native
- name: Install dashboard dependencies
run: npm install --prefix src/dashboard --ignore-scripts
- name: Run dashboard tests
run: npm run test:dashboard
timeout-minutes: 5
test-windows:
name: Tests — Windows (allow-failure)
# 535: the merge queue re-runs required checks on the final merge result —
# for this workflow that is Type Check alone. Every other job re-running in
# the queue added ~30min wall-clock per train with no admission value
# (main-push still runs the full matrix).
if: github.event_name != 'merge_group'
runs-on: windows-latest
# Windows is unsupported — this job is informational only
continue-on-error: true
needs: typecheck
steps:
- uses: actions/checkout@v4
# Windows Git keeps long-path support default-off. This must be injected
# into checkout's own Git processes (a prior global-config step is not
# sufficient because actions/checkout temporarily replaces HOME).
env:
GIT_CONFIG_COUNT: '1'
GIT_CONFIG_KEY_0: core.longpaths
GIT_CONFIG_VALUE_0: 'true'
- uses: actions/setup-node@v4
with:
node-version: '24.x'
cache: npm
- run: npm ci
- run: npm run ci:rebuild-native
- name: Run core tests (Windows informational)
run: npx vitest run tests/core/ tests/agents/
timeout-minutes: 10
continue-on-error: true
build:
name: Build
# 535: the merge queue re-runs required checks on the final merge result —
# for this workflow that is Type Check alone. Every other job re-running in
# the queue added ~30min wall-clock per train with no admission value
# (main-push still runs the full matrix).
if: github.event_name != 'merge_group'
runs-on: ubuntu-latest
needs: [test-core, test-orchestra, test-cli, test-remaining, test-dashboard]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24.x'
cache: npm
- run: npm ci
- run: npm run ci:rebuild-native
- name: Install dashboard dependencies
run: npm install --prefix src/dashboard --ignore-scripts
- run: npm run build
- name: Verify dist
run: |
test -f dist/cli/index.js
test -f dist/cli/entry.js
test -f dist/mcp/server.js
test -f dist/index.js
head -1 dist/cli/entry.js | grep -q "#!/usr/bin/env node"
head -1 dist/mcp/server.js | grep -q "#!/usr/bin/env node"
shards-green:
name: Shards Green
# D5 aggregate required check (owner decision 2026-08-11). Incident class:
# PR #120 merged with red shards because the ruleset required only Type Check
# and the three Validator legs. This job fans in every test shard, so the
# ruleset needs exactly ONE new required context and never has to be re-edited
# when the matrix changes.
#
# always() is what makes the gate real: without it a failed shard would leave
# this job skipped, and a skipped required check reports as passing.
# Row 535 is preserved — the merge queue re-runs Type Check alone and skips
# every shard, so the aggregate stays out of merge_group too.
if: always() && github.event_name != 'merge_group'
runs-on: ubuntu-latest
needs:
- test-core
- test-orchestra
- test-cli
- test-remaining
- test-docs-scripts
- test-dashboard
- test-windows
steps:
- name: Assert every shard concluded green
env:
NEEDS_JSON: ${{ toJSON(needs) }}
# Minimum fan-in width. A shard silently dropped from the needs list
# above shrinks this object, and the gate then fails instead of
# reporting green on a matrix that no longer covers the repo.
# tests/scripts/ci-aggregate-gate.test.ts pins this number to the live
# `Tests —` job inventory.
MINIMUM_SHARDS: '7'
run: |
node -e '
const needs = JSON.parse(process.env.NEEDS_JSON || "{}");
const minimum = Number(process.env.MINIMUM_SHARDS);
const event = process.env.GITHUB_EVENT_NAME || "";
const entries = Object.entries(needs);
let failed = false;
const fail = (message) => { failed = true; console.log("::error::" + message); };
console.log("event=" + event + " fanned-in=" + entries.length + " minimum=" + minimum);
for (const [id, job] of entries) console.log(" " + id + " => " + job.result);
if (!Number.isInteger(minimum) || minimum < 1) {
fail("MINIMUM_SHARDS must be a positive integer, got: " + process.env.MINIMUM_SHARDS);
} else if (entries.length < minimum) {
fail("Shards Green fanned in " + entries.length + " job(s) but " + minimum + " are required. A shard was dropped from the needs list, so the aggregate refuses to report green on partial coverage.");
}
// A skipped shard is legitimate only under the row-535 merge_group
// guard, and that tolerance is read from the event rather than from a
// hardcoded per-job allowlist. On pull_request/push a skip means the
// shard never ran (upstream failure), which is not green.
const skipIsLegitimate = event === "merge_group";
const notGreen = entries.filter(([, job]) => job.result !== "success" && !(skipIsLegitimate && job.result === "skipped"));
if (notGreen.length > 0) {
fail("shard(s) did not conclude green: " + notGreen.map(([id, job]) => id + "=" + job.result).join(", "));
}
if (failed) process.exit(1);
console.log("All " + entries.length + " shards concluded green.");
'