feat(server): reject draft-only GGUF + support --model-draft (MTP speculative decoding) #110
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| workflow_dispatch: | |
| jobs: | |
| python-tests: | |
| name: Python tests (Windows, ${{ matrix.python-version }}) | |
| runs-on: windows-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.11", "3.12", "3.13"] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: pip | |
| cache-dependency-path: pyproject.toml | |
| - name: Install | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[server,test]" | |
| - name: Run tests | |
| run: python -m pytest -q | |
| hermetic-tests: | |
| # Lesson (2026-08-11): tiering pin/unpin tests passed locally for 6 | |
| # pushes while CI was red, because they depended on real model files | |
| # in ~/models that only exist on the dev machine. This pass runs the | |
| # full suite with an empty HOME/USERPROFILE so any test that quietly | |
| # reads files outside the repo fails here instead of silently passing | |
| # on dev machines. See research/2026-08-11-lesson-ci-hermetic-tests.md | |
| name: Python tests — empty HOME (hermetic guard) | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| cache: pip | |
| cache-dependency-path: pyproject.toml | |
| - name: Install | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[server,test]" | |
| - name: Run tests (no files outside the repo exist) | |
| env: | |
| # A path that cannot exist → any test touching machine-local | |
| # files (real models, dev home) fails exactly like on a fresh box. | |
| # Single quotes: `\e` would be a YAML escape in double quotes. | |
| HOME: '${{ runner.temp }}\empty-home' | |
| USERPROFILE: '${{ runner.temp }}\empty-home' | |
| run: python -m pytest -q | |
| frontend: | |
| name: Frontend typecheck + build | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: frontend | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: npm | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install | |
| run: npm ci | |
| - name: Security audit (npm audit) | |
| # Fails when a moderate-or-higher vulnerability is present in the | |
| # dependency tree (including transitive), so new advisories break | |
| # CI instead of being noticed later via GitHub dependabot alerts. | |
| run: npm audit --audit-level=moderate | |
| - name: Typecheck | |
| run: npm run typecheck | |
| - name: Unit tests (vitest) | |
| run: npm test | |
| - name: Build | |
| run: npm run build | |
| - name: Bundle freshness guard (committed console bundle must match source) | |
| # Fail when rebuilding the frontend changes the committed console | |
| # bundle (weight_stream/server/static/console). A stale bundle means | |
| # the served console is missing features that exist in source — this | |
| # happened on 2026-08-13: auto-compact + n_ctx/max_tokens landed in | |
| # source but the committed bundle predated them (a049cd0), so anyone | |
| # cloning the repo got a console without those features. | |
| run: | | |
| if ! git diff --exit-code -- ../weight_stream/server/static/console/ >/dev/null; then | |
| echo "::error::Committed console bundle is stale — rebuild it and commit: cd frontend && npm run build" | |
| git diff --stat -- ../weight_stream/server/static/console/ | |
| exit 1 | |
| fi | |
| echo "console bundle is in sync with source" |