Skip to content

fix(xtiles): the loaded-view gate now matches the app, and passes #140

fix(xtiles): the loaded-view gate now matches the app, and passes

fix(xtiles): the loaded-view gate now matches the app, and passes #140

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- run: uv sync --locked --all-packages --group dev
- run: uv run --group dev ruff check .
- run: uv run --group dev ruff format --check .
typecheck:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b
- run: uv sync --locked --all-packages --group dev
- run: just typecheck
sast:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- run: uv sync --locked --all-packages --group dev
- name: Run bandit (SAST)
# Skip list mirrors .pre-commit-config.yaml's bandit hook, which
# documents each rule. B608 (dynamic SQL) in particular is skipped
# project-wide because every hit was verified individually in the
# 2026-09 security review: each interpolates only a server-side
# allowlisted column name or a `?`-placeholder count, never raw
# user data; actual values always go through bound parameters.
run: uv run --group dev bandit --recursive --skip B101,B104,B105,B106,B107,B108,B110,B310,B404,B603,B606,B607,B608 packages/
audit:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- run: uv sync --locked --all-packages --group dev
- name: Audit dependencies for known vulnerabilities
run: |
uv --quiet export --all-packages --group dev --no-emit-workspace --format requirements-txt -o /tmp/requirements.txt
uv tool run pip-audit -r /tmp/requirements.txt --strict --no-deps --disable-pip
audit-full:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- run: uv sync --locked --all-packages --group dev --all-extras
- name: Audit full optional dependency surface
run: |
uv --quiet export --all-packages --group dev --all-extras --no-emit-workspace --format requirements-txt -o /tmp/requirements-full.txt
uv tool run pip-audit -r /tmp/requirements-full.txt --strict --no-deps --disable-pip
test:
runs-on: ubuntu-latest
timeout-minutes: 25
strategy:
fail-fast: false # report every Python version independently; don't cancel siblings
matrix:
python-version: ["3.12", "3.13"]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: ${{ matrix.python-version }}
- run: uv sync --locked --all-packages --group dev
- run: uv run --group dev pytest --tb=short --cov=packages --cov-report=term-missing
js:
# The browser-side unit tests (87 at time of writing) previously ran in NO
# gate: no workflow and no just recipe invoked them, so they only executed if
# someone typed `node --test` by hand. A suite nothing runs cannot be evidence
# of anything, which is the same blind spot that hid three regressions in the
# unrun e2e suites.
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: "22"
- run: node --test packages/studyloop/tests/js/*.test.js
web-profile:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b
- run: uv sync --locked --all-packages --group dev --extra web
- run: just test-web
browser-smoke:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b
- run: uv sync --locked --all-packages --group dev --extra web
- run: uv run playwright install --with-deps chromium
- run: just test-browser-smoke
e2e:
# The other 39 e2e files. Until this job existed only the single smoke file
# above ran in any gate, so ~500 browser tests were evidence of nothing --
# the same blind spot called out for the JS tests in the `js` job. Two real
# defects were hiding in there: a 500 from a file-deletion race in session
# teardown, and a 200ms sleep racing a 187ms CSS fade.
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b
# tmux, but deliberately NOT ttyd. This mirrors the environment where the
# 500-pass unscaled result was actually verified, which had tmux and no
# ttyd. ttyd's absence is itself under test --
# test_terminal_proxy_degrades_when_ttyd_is_absent asserts the proxy
# answers 502 rather than hanging -- so installing it would diverge CI
# from the proven configuration and weaken that contract. Do not "fix"
# this by adding ttyd.
- run: sudo apt-get update && sudo apt-get install -y tmux
- run: uv sync --locked --all-packages --group dev --extra web
- run: uv run playwright install --with-deps chromium
# A missing dependency makes this suite SKIP rather than fail, so "0
# failed" would survive a run that executed almost nothing. The floor is
# set below the 500 currently passing so ordinary growth or a legitimate
# new skip does not trip it, while a collapse to a hollow green does.
- run: just e2e
env:
STUDYLOOP_MIN_PASSED: "450"
# The e2e tests already screenshot the page and dump its HTML when they
# fail (_diag in the journey files), but nothing collected those, so every
# CI failure had to be diagnosed from a stack trace alone -- a
# wait_for_function timeout says only that a condition never became true,
# never what the page actually showed instead. Uploading them turns the
# next failure into evidence rather than a hypothesis.
#
# if: failure() rather than always(): on a green run there is nothing to
# collect, and an empty artifact per run is noise.
- if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: e2e-failure-diagnostics
path: |
test-results/
packages/studyloop/test-results/
retention-days: 7
if-no-files-found: warn
content-profile:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b
- run: uv sync --locked --all-packages --group dev --extra content
- run: just test-content
semantic-profile:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- uses: extractions/setup-just@f8a3cce218d9f83db3a2ecd90e41ac3de6cdfd9b
- run: uv sync --locked --all-packages --group dev --extra semantic
- run: just test-semantic
build:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- run: ./scripts/build-release.sh
- run: uv run python scripts/check-release-consistency.py
install-smoke:
runs-on: ubuntu-latest
timeout-minutes: 15
needs: build
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@e4db8464a088ece1b920f60402e813ea4de65b8f # v4
with:
python-version: "3.12"
- name: Build and smoke-test installed wheel
run: |
./scripts/build-release.sh
tmp="$(mktemp -d)"
uv venv "$tmp/venv"
uv pip install --python "$tmp/venv/bin/python" dist/studyloop-*.whl packages/agent-session-tools
STUDYLOOP_EXPECT_BIN_DIR="$tmp/venv/bin" PATH="$tmp/venv/bin:$PATH" ./scripts/smoke-installed-cli.sh