name: CI on: push: branches: [main] pull_request: workflow_dispatch: jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # The bundle's own checks come first, before anything else can run. # Both read only data/, lib/ and fixtures/ and exit non-zero on failure: # validate.mjs — curriculum sequencing. Baseline: PASS, 0 blocking, 0 advisory. # audit-gate.mjs — the word gate against 54 real tutor messages. # Baseline: 7 of 41 and 2 of 13 flagged. Too many # means it rejects real teaching; too few means # violations reach the student. - name: Curriculum validation and gate audit run: sh run-checks.sh - uses: actions/setup-node@v4 with: node-version: 22 cache: npm - run: npm ci - name: Typecheck run: npm run typecheck # The sync round-trip needs a real Postgres and a running server: a fake # would not exercise the compare-and-swap push, the advisory locks that # keep a pull from skipping a change_seq, or cursor paging — which is # where sync actually goes wrong. - name: Start Postgres run: | docker run -d --name hankan-pg \ -e POSTGRES_PASSWORD=test -e POSTGRES_DB=hankan \ -p 55432:5432 postgres:16-alpine for i in $(seq 1 30); do docker exec hankan-pg pg_isready -U postgres -d hankan && break sleep 1 done - name: Start the sync server env: DATABASE_URL: postgres://postgres:test@localhost:55432/hankan HANKAN_TOKEN: test-token HANKAN_TEST_MODE: "1" # Keyless, so the tutor endpoint is exercised over real HTTP — # SSE framing, CORS and auth — without an Anthropic key in CI. HANKAN_TUTOR_BACKEND: echo PORT: "8788" run: | node --experimental-strip-types server/src/main.ts & for i in $(seq 1 30); do curl -sf http://localhost:8788/health && break sleep 1 done - name: Tests env: HANKAN_TEST_SERVER: http://localhost:8788 run: npm test # Every word in every unit's words[] must resolve in lemma or surface. # Runs against the committed band files in app/public/dict/. - name: Roadmap word coverage run: npm run dict:assert - name: Build run: npm run build