Skip to content

Claudinite growth: conversation extract (#575) #312

Claudinite growth: conversation extract (#575)

Claudinite growth: conversation extract (#575) #312

Workflow file for this run

# The CANON repo's own CI — Claudinite's test suite + its own conformance sweep
# on every PR. Not consumer wiring (consumers ship no workflow, #385).
name: CI
on:
pull_request:
push:
branches: [main]
# Dispatchable so a GITHUB_TOKEN-authored PR (whose push/open GitHub never
# turns into a pull_request run — the recursion guard) can still get this
# suite started on its branch: baselining's deliver() and any bot flow like
# migrations-retire's archive PR (#432, #565) dispatch it explicitly.
workflow_dispatch:
defaults:
run:
shell: bash
jobs:
test-and-conformance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# Check out the PR's real head, not the synthetic refs/pull/N/merge commit
# actions/checkout uses by default — otherwise HEAD is an ephemeral merge of
# the branch into main, which the work-scoped squash-merge-history check would
# (correctly, for that synthetic commit) flag. This makes CI evaluate exactly
# what the local Stop hook does: the branch tip. Falls back to github.sha on push.
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Unit tests
# THE test roots — a closed set of FOLDERS, each swept to any depth. Depth is
# deliberately not enumerated: the previous form spelled out one glob per level
# (`packs-tests/*/skills/*/*.test.mjs` and so on), so a test at an unlisted depth
# was silently never run — which is exactly how vendoring/'s two files sat outside
# CI. `**` removes depth from the question; what remains is the root list, and
# engine-tests/ci-test-roots.test.mjs fails the moment a tracked test lands
# outside it. Adding a root is a deliberate CI edit; adding a test is not.
# engine-tests/ engine/ + the other top-level canon code (migrations/, …);
# mirrors engine/'s inner structure, and stays canon-side
# because engine/ ships to consumers exactly as-is (#385)
# packs-tests/ every canon pack's tests, mirroring packs/
# vendoring/ co-located with the vendor computer/writer they cover
# dev/tools/ maintainer-side tooling nothing at session time runs
# .claudinite/local/packs/ this repo's own local packs — tests live inside the tree
# nullglob: a root with no tests drops out instead of reaching node as a literal pattern.
run: |
shopt -s globstar nullglob
tests=(engine-tests/**/*.test.mjs packs-tests/**/*.test.mjs vendoring/**/*.test.mjs dev/tools/**/*.test.mjs .claudinite/local/packs/**/*.test.mjs)
node --test "${tests[@]}"
- name: Conformance sweep
# The world sweep's home is the test/CI flow (not the Stop hook, which
# carries only the work scope) — this canon repo models the pattern
# bootstrap wires into consumers. World only: the work scope judges a
# session's change and runs at that session's Stop hook, not here.
run: node engine/checks/check_the_world.mjs
- name: Promote write-surface gate
# The growth promote stage (.claudinite/local/packs/canon-curation/tasks/growth-promote/task.md)
# is the one change bounded to packs/ + skills/ — an ordinary engine PR legitimately edits
# checks/ and engine/, so this cannot run on every PR. It keys on the promote branch prefix
# (the task doc pins it) and fails the promote PR if a changed path strays.
if: contains(github.head_ref, 'growth-promote')
run: node .claudinite/local/packs/canon-curation/promote-scope.mjs