Repository navigation
261 lines (248 loc) · 13.4 KB
/
Copy pathcheck.yml
File metadata and controls
261 lines (248 loc) · 13.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
# CI: run the repo's own dependency-free gate (`make check` = clean + portable
# CPU build + C unit suites + Python stdlib tests) on the three claimed
# platforms. No model downloads, no CUDA, no external deps — by design (#140).
name: check
on:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]
permissions:
contents: read
concurrency:
group: check-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
PYTHONUTF8: '1'
jobs:
linux:
name: Linux
runs-on: ubuntu-latest
# make check built serially and took 23 minutes on 2026-10-17, then past 25 with two
# more engines' GGUF code: the builds now use every core (make test runs the C and
# Python suites one after the other, so only the compiling is parallel).
timeout-minutes: 35
steps:
- uses: actions/checkout@v4
- name: make check
run: make -C c -j"$(nproc)" check
windows:
# The job that would have caught #68/#137 pre-merge: native MinGW-w64
# (MSYS2/UCRT64), the exact toolchain the README's Windows port targets.
name: Windows UCRT64
runs-on: windows-latest
# Measured, not guessed: this job now runs 19-21 minutes, so a 20-minute
# limit decided the result by runner luck. Three consecutive runs on
# 2026-08-27 took 19m21s (passed), 20m18s and 20m32s (both cancelled at the
# limit and reported as failures), including one on dev itself. The suite
# has grown - segment conformance and adapters, the edge runtime, per-engine
# cache indices - and MinGW is the slowest toolchain we build on.
# 2026-10-05: the 35 minutes set then were reached in turn. Over the last
# two days the job took 21 to 34 minutes when it passed, and was cancelled
# at 35 three times with every test passed so far (#1907, #1911 and a dev
# run), after #1901 added its suites. 60 leaves room for the suites still
# coming; a real hang still ends the job.
# 2026-10-20: reached again. The job took 45 to 57 minutes when it passed
# (#2265 twice, #2266), and was cancelled at 60 twice, once 5 seconds after
# its 2695 tests had passed (#2267). 90.
timeout-minutes: 90
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
with:
msystem: UCRT64
update: false
install: >-
make
mingw-w64-ucrt-x86_64-gcc
mingw-w64-ucrt-x86_64-python
- name: make check
run: make -C c check
# The Windows engine as this branch builds it. Small, and it makes an
# antivirus false-positive report (#527) verifiable on a PR instead of
# only after a release is tagged and published.
- uses: actions/upload-artifact@v4
with:
name: colibri-windows-exe
path: c/colibri.exe
k3-tiny:
name: Linux (generated tiny K3 vendor oracle)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: pip
cache-dependency-path: c/tools/requirements-kimi-k3-tiny.txt
- name: Install pinned tiny-fixture dependencies
run: python -m pip install -r c/tools/requirements-kimi-k3-tiny.txt
- name: Generate fixture and run vendor oracle
run: make -C c kimi-k3-tiny-check
mimo-tiny:
name: Linux (generated tiny MiMo-V2.6 vendor oracle, text + vision)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: pip
cache-dependency-path: c/tools/requirements-mimo-tiny.txt
- name: Install pinned tiny-fixture dependencies
run: python -m pip install -r c/tools/requirements-mimo-tiny.txt
- name: Generate fixture and run vendor oracle
run: make -C c mimo-tiny-check
- name: "Brio and the prompt cache: photos exact against a cold engine"
run: make -C c mimo-tiny-serve-check
- name: Same oracle under ASan and UBSan
run: |
make -C c clean >/dev/null
make -C c mimo EXTRA_CFLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -g"
ASAN_OPTIONS=detect_leaks=0:detect_stack_use_after_return=0 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 \
python c/tests/mimo_tiny_harness.py --binary c/mimo --fixture c/mimo_tiny
cd c && ASAN_OPTIONS=detect_leaks=0:detect_stack_use_after_return=0 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 \
python -m unittest tests.test_mimo_prefix_serve tests.test_brio_serve.MimoBrioServe \
tests.test_systemone_api.MimoSystemOneEndToEnd
v4-tiny:
name: Linux (generated tiny V4 target oracle)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: pip
cache-dependency-path: c/tools/requirements-deepseek-v4-tiny.txt
- name: Install pinned tiny-fixture dependencies
run: python -m pip install -r c/tools/requirements-deepseek-v4-tiny.txt
- name: Generate fixture and run target oracle
run: make -C c deepseek-v4-tiny-check
glm53-oracle:
name: Linux (generated GLM-5.3 oracle contract)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: pip
cache-dependency-path: c/tools/requirements-glm53-tiny.txt
- name: Install pinned oracle dependencies
run: python -m pip install -r c/tools/requirements-glm53-tiny.txt
- name: Generate and validate oracle contract
run: |
python c/tools/make_glm53_tiny.py --output /tmp/glm53_tiny
python c/tools/check_glm53_checkpoint.py --model /tmp/glm53_tiny
# The dashboard's Brain and Profile tabs read EMAP/HITS/PROF from the
# engine's stdout. GLM-5.3-Flash emitted none of them and both tabs were
# blank (Discord, 2026-09-06). This drives the built engine through
# `coli serve` and the /experts and /profile endpoints on a streaming
# fixture, the same path the dashboard takes, so a family that stops
# emitting a line fails here and not on a user's screen.
- name: Build glm53 and check the dashboard contract
run: |
make -C c glm53
python c/tools/make_glm53_multimodal_tiny.py --output /tmp/glm53_mm
python c/tools/make_glm53_streaming_pair.py --fixture /tmp/glm53_mm --output /tmp/glm53_stream
python c/tools/make_edge_tiny_tokenizer.py --vocab-size 281 /tmp/glm53_stream-i4
cd c && COLI_GLM53_FIXTURE=/tmp/glm53_stream-i4 python -m unittest -v tests.test_glm53_dashboard
COLI_GLM53_FIXTURE=/tmp/glm53_stream-i4 python -m unittest -v tests.test_glm53_context_exceeded
COLI_GLM53_FIXTURE=/tmp/glm53_stream-i4 python -m unittest -v tests.test_glm53_hostile_weights
COLI_GLM53_FIXTURE=/tmp/glm53_mm python -m unittest -v tests.test_glm53_hostile_weights.Glm53MatrixShapeTest
COLI_GLM53_FIXTURE=/tmp/glm53_stream-i4 python -m unittest -v tests.test_glm53_cluster
# The two stdlib-only oracles used to be argparse scripts that `make
# test-python` collected as zero tests (#1700). They run here, on the
# fixtures generated above, token-exact against transformers in f32.
- name: Run the GLM-5.3 tiny oracles
run: |
cd c && GLM53_TINY=/tmp/glm53_tiny GLM53_MM_TINY=/tmp/glm53_mm python -m unittest -v tests.test_glm53_oracles
GLM53_TINY=/tmp/glm53_tiny COLI_GLM53_FIXTURE=/tmp/glm53_stream-i4 python -m unittest -v tests.test_glm53_prefill_batch
COLI_GLM53_FIXTURE=/tmp/glm53_mm python -m unittest -v tests.test_glm53_accept
qwen36-oracle:
name: Linux (generated qwen36 oracles)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: pip
cache-dependency-path: c/tools/requirements-glm53-tiny.txt
- name: Install pinned oracle dependencies
run: python -m pip install -r c/tools/requirements-glm53-tiny.txt
# Flint's layer (a sink per head, sliding-window layers, layers without RoPE, dense
# layers in front, sigmoid routing) token for token against tools/make_flint_tiny.py's
# float32 reference, the GGUF read in place with F32 and with Q8_0 experts.
- name: Build qwen36 and run the Flint tiny oracles
run: |
make -C c qwen36
cd c
for experts in F32 Q8_0; do
python tools/make_flint_tiny.py --out /tmp/flint_$experts --emit-ref /tmp/flint_$experts/ref.json \
--gguf /tmp/flint_$experts/model.gguf --gguf-experts $experts
COLI_CUDA=0 COLI_VULKAN=0 SNAP=/tmp/flint_$experts/model.gguf ./qwen36 16 8 /tmp/flint_$experts/ref.json
# the KV cache in float16, as a serve keeps it (a .json reference keeps float32 unless Q36_KV says)
COLI_CUDA=0 COLI_VULKAN=0 Q36_KV=f16 SNAP=/tmp/flint_$experts/model.gguf ./qwen36 16 8 /tmp/flint_$experts/ref.json
# the sliding layers' KV in a ring of window + 9 rows (the least spare), shorter than the run
COLI_CUDA=0 COLI_VULKAN=0 Q36_KV_RING_SPARE=9 SNAP=/tmp/flint_$experts/model.gguf ./qwen36 16 8 /tmp/flint_$experts/ref.json 2> ring.log
grep -q 'sliding-window layers keep a ring of 14 rows' ring.log || { cat ring.log; exit 1; }
done
# Muse Spark's layer (residual gates, the experts at their own width between two
# projections, a norm on every expert's output, capped logits) against
# tools/make_muse_tiny.py's reference, F32 experts and Q8_0 ones (the reference then
# quantizes the experts' inputs as the CPU's integer kernels do).
- name: Run the Muse Spark tiny oracles
run: |
cd c
python tools/make_muse_tiny.py --out /tmp/muse_F32 --emit-ref /tmp/muse_F32/ref.json --experts F32
COLI_CUDA=0 COLI_VULKAN=0 SNAP=/tmp/muse_F32/model.gguf ./qwen36 16 8 /tmp/muse_F32/ref.json
COLI_CUDA=0 COLI_VULKAN=0 Q36_KV_RING_SPARE=9 SNAP=/tmp/muse_F32/model.gguf ./qwen36 16 8 /tmp/muse_F32/ref.json 2> ring.log
grep -q 'sliding-window layers keep a ring of 14 rows' ring.log || { cat ring.log; exit 1; }
# Q8_0: the experts' inputs round to int8 from sums whose order differs from one CPU
# to the next (a code apart moved a 0.106 margin at the 16th token on AVX-VNNI), so
# this one is shorter and wider apart
python tools/make_muse_tiny.py --out /tmp/muse_Q8_0 --emit-ref /tmp/muse_Q8_0/ref.json --experts Q8_0 --max-new 8 --min-gap 0.2
COLI_CUDA=0 COLI_VULKAN=0 SNAP=/tmp/muse_Q8_0/model.gguf ./qwen36 16 8 /tmp/muse_Q8_0/ref.json
# LFM3's layers (short gated convolutions beside attention with a gate per head, the
# full layers' partial rotation, every branch normalised) against
# tools/make_lfm3_tiny.py's float32 reference, F32 matrices and Q8_0 ones.
- name: Run the LFM3 tiny oracles
run: |
cd c
python tools/make_lfm3_tiny.py --out /tmp/lfm3_F32 --emit-ref /tmp/lfm3_F32/ref.json
COLI_CUDA=0 COLI_VULKAN=0 SNAP=/tmp/lfm3_F32/model.gguf ./qwen36 16 8 /tmp/lfm3_F32/ref.json
COLI_CUDA=0 COLI_VULKAN=0 Q36_KV=f16 COLI_LOOKUP=0 SNAP=/tmp/lfm3_F32/model.gguf ./qwen36 16 8 /tmp/lfm3_F32/ref.json
COLI_CUDA=0 COLI_VULKAN=0 Q36_KV_RING_SPARE=9 SNAP=/tmp/lfm3_F32/model.gguf ./qwen36 16 8 /tmp/lfm3_F32/ref.json 2> ring.log
grep -q 'sliding-window layers keep a ring of 14 rows' ring.log || { cat ring.log; exit 1; }
python tools/make_lfm3_tiny.py --out /tmp/lfm3_Q8_0 --emit-ref /tmp/lfm3_Q8_0/ref.json --dense Q8_0 --max-new 8 --min-gap 0.2
COLI_CUDA=0 COLI_VULKAN=0 SNAP=/tmp/lfm3_Q8_0/model.gguf ./qwen36 16 8 /tmp/lfm3_Q8_0/ref.json
# LFM3-VL's tower (lfm3_vision.h) from an mmproj: a picture's rows within 1e-4 of the
# reference's, and the continuation they lead to
python tools/make_lfm3_tiny.py --out /tmp/lfm3_V --emit-ref /tmp/lfm3_V/ref.json --vision
COLI_CUDA=0 COLI_VULKAN=0 Q36_MMPROJ=/tmp/lfm3_V/mmproj.gguf Q36_VIS_DUMP=/tmp/lfm3_V/rows.bin SNAP=/tmp/lfm3_V/model.gguf ./qwen36 16 8 /tmp/lfm3_V/ref.json
python -c "import numpy as n; a=n.fromfile('/tmp/lfm3_V/rows.bin','f4'); b=n.fromfile('/tmp/lfm3_V/image_rows.f32','f4'); e=abs(a-b).max()/n.sqrt((b*b).mean()); print('LFM3 vision rows, worst error of the rms', e); assert a.shape==b.shape and e<1e-4"
macos:
# clang; libomp for the threaded path (Makefile falls back to
# single-threaded automatically if it's ever missing).
name: macOS (colibri + V4 platform gate)
runs-on: macos-latest
# `make check` here now takes about 14.5 minutes; at 15 the job was cut
# off inside the Python suite with no test failed, and showed as red.
# 2026-10-24 it took 24 minutes, and on the next run the suite printed
# OK at 25:00, the moment the job was cut off: 35 leaves the room again.
timeout-minutes: 35
steps:
- uses: actions/checkout@v4
- name: install libomp
run: brew install libomp
- name: make check (V4 execution gated off)
run: make -C c check