diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05fc7dd..2c87a98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,9 +17,9 @@ env: jobs: changes: # Classify a pull request so a leaf-module edit runs a fast, deterministic - # check set instead of the full matrix (hq#14). Runs on a GitHub-hosted - # runner so it is never itself queued behind the self-hosted pool it exists - # to shorten; a `push` to main always takes the full path. + # check set instead of the full matrix (hq#14). It runs on a GitHub-hosted + # runner so classification never depends on workstation state; a `push` to + # main always takes the full path. runs-on: ubuntu-latest outputs: leaf: ${{ steps.classify.outputs.leaf }} @@ -54,9 +54,8 @@ jobs: echo "leaf=$leaf" >> "$GITHUB_OUTPUT" lint: # Static checks are interpreter-version agnostic; run them once. - # GitHub-hosted on purpose: spikeforge is public, so hosted minutes are - # free, and this keeps the *required* checks off the three self-hosted - # runners whose queue was the fleet's bottleneck (hq#14). + # GitHub-hosted because this public repository's CI is intentionally + # independent of workstation state. runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -85,9 +84,8 @@ jobs: test: # The full suite across every supported interpreter (python_requires). needs: changes - # GitHub-hosted on purpose: spikeforge is public, so hosted minutes are - # free, and this keeps the *required* checks off the three self-hosted - # runners whose queue was the fleet's bottleneck (hq#14). + # GitHub-hosted because this public repository's CI is intentionally + # independent of workstation state. runs-on: ubuntu-latest strategy: fail-fast: false @@ -126,7 +124,7 @@ jobs: # exits 0 *and* that the JSON carries one cell per registered target. needs: changes if: needs.changes.outputs.leaf != 'true' - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -179,7 +177,7 @@ jobs: # source and its offline catalog/CLI work. needs: changes if: needs.changes.outputs.leaf != 'true' - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -217,7 +215,7 @@ jobs: # `spikeforge-hub` distribution, exercised by the `hub` job above. needs: changes if: needs.changes.outputs.leaf != 'true' - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest strategy: fail-fast: false matrix: @@ -281,7 +279,7 @@ jobs: # enumerated with `--ignore` below; everything else runs under the blocker. needs: changes if: needs.changes.outputs.leaf != 'true' - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest env: PYTHONPATH: ${{ github.workspace }}/scripts/blocked_deps steps: @@ -351,7 +349,7 @@ jobs: # the `published-surfaces` job below covers what readers actually land on. needs: changes if: needs.changes.outputs.leaf != 'true' - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -377,9 +375,8 @@ jobs: # # Deliberately torch-free: readme_renderer plus the stdlib is the whole # dependency set, so this stays one of the fastest jobs in the matrix. - # GitHub-hosted on purpose: spikeforge is public, so hosted minutes are - # free, and this keeps the *required* checks off the three self-hosted - # runners whose queue was the fleet's bottleneck (hq#14). + # GitHub-hosted because this public repository's CI is intentionally + # independent of workstation state. runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -406,7 +403,7 @@ jobs: # types is still caught here. needs: changes if: needs.changes.outputs.leaf != 'true' - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -432,9 +429,8 @@ jobs: # The static half of the core boundary: no module-level import of a # forbidden root, and no function-local import outside the lazy shims. # Pure stdlib, so no dependencies are installed. - # GitHub-hosted on purpose: spikeforge is public, so hosted minutes are - # free, and this keeps the *required* checks off the three self-hosted - # runners whose queue was the fleet's bottleneck (hq#14). + # GitHub-hosted because this public repository's CI is intentionally + # independent of workstation state. runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -452,7 +448,7 @@ jobs: # distributions, and must not contain `server/`. needs: changes if: needs.changes.outputs.leaf != 'true' - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -514,9 +510,8 @@ jobs: packaging-guards: # The three lightweight topology guards: disjoint import roots (PEP 420), # console-script ownership, and satellite pins == compatibility.json. - # GitHub-hosted on purpose: spikeforge is public, so hosted minutes are - # free, and this keeps the *required* checks off the three self-hosted - # runners whose queue was the fleet's bottleneck (hq#14). + # GitHub-hosted because this public repository's CI is intentionally + # independent of workstation state. runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/deploy-hetzner.yml b/.github/workflows/deploy-hetzner.yml index 9d06482..c445629 100644 --- a/.github/workflows/deploy-hetzner.yml +++ b/.github/workflows/deploy-hetzner.yml @@ -20,7 +20,7 @@ permissions: jobs: deploy: - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index 6e36838..5959a4c 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -25,7 +25,7 @@ concurrency: jobs: build: - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -55,7 +55,7 @@ jobs: deploy: needs: build - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} diff --git a/.github/workflows/hub-verify.yml b/.github/workflows/hub-verify.yml index 5f401a9..61f249b 100644 --- a/.github/workflows/hub-verify.yml +++ b/.github/workflows/hub-verify.yml @@ -13,9 +13,8 @@ name: Hub artifact verification (sandbox) # # This job runs `torch.load` on bytes a stranger uploaded. It MUST stay # on a GitHub-hosted, ephemeral runner. It must NEVER run on the -# self-hosted `spikeforge-ci` runner that `deploy-hetzner.yml` uses -- -# that runner holds the Hetzner deploy key, and running untrusted-content -# code on a persistent self-hosted runner is named in the plan (§7.2) as +# persistent workstation runner -- any such runner could hold deployment +# credentials, and running untrusted-content code on it is named in the plan (§7.2) as # the single most predictable way this whole design could be # compromised. This is deliberately the first workflow in this repository # that does not use `spikeforge-ci`. @@ -42,7 +41,7 @@ env: jobs: verify: # GitHub-hosted only -- see the header comment. Do not add - # `spikeforge-ci` or any other self-hosted label to this job. + # any self-hosted label to this job. runs-on: ubuntu-latest # A wall-clock ceiling independent of any one step's own timeout, per # plans/hub_accounts_plan.md §7.2 ("a wall-clock timeout"). diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 694aacc..d2d0257 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: # job start and cannot see another step's outputs in the same job, # only a prior job's via `needs.*.outputs`. name: Parse ${{ github.ref_name }} - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest outputs: distribution: ${{ steps.parse.outputs.distribution }} version: ${{ steps.parse.outputs.version }} @@ -44,7 +44,7 @@ jobs: release: name: Publish ${{ github.ref_name }} needs: parse - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest # Named after the distribution (e.g. "spikeforge-hub") so it matches # that PyPI project's trusted-publisher "Environment name" -- required # because every distribution shares this same repo + workflow file, diff --git a/.github/workflows/wiki-sync.yml b/.github/workflows/wiki-sync.yml index 2eb233d..8a479ab 100644 --- a/.github/workflows/wiki-sync.yml +++ b/.github/workflows/wiki-sync.yml @@ -22,7 +22,7 @@ concurrency: jobs: sync: - runs-on: [self-hosted, linux, x64, spikeforge-ci] + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/capsize.json b/capsize.json new file mode 100644 index 0000000..6ff4e8a --- /dev/null +++ b/capsize.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://raw.githubusercontent.com/Capsize-Games/capsize-ci/1a50d06c20022f9bbc44bad002add302e1dae646/schema/capsize-1.json", + "schema_version": 1, + "standards": "1.x", + "name": "spikeforge", + "type": "app", + "languages": ["python", "typescript", "javascript", "css", "html"], + "framework": "fastapi-react", + "databases": [], + "runtimes": { "python": ">=3.11", "node": ">=22" }, + "entrypoints": { + "server": "server/__main__.py", + "client": "client/package.json", + "cli": "main.py" + }, + "task_runner": "just", + "commands": { + "setup": "setup", + "build": "build", + "test": "test", + "lint": "lint", + "format": null, + "typecheck": "typecheck", + "run": "run", + "clean": null, + "docs": "docs", + "ci": "ci" + }, + "dependencies": { + "python": "requirements.txt", + "node": "client/package.json", + "npm": "client/package-lock.json" + }, + "instructions": { + "canonical": "AGENTS.md", + "rules": [ + "capsize/base", + "capsize/python", + "capsize/web" + ] + }, + "owner": "Capsize-Games", + "license": "BSD-3-Clause" +} diff --git a/justfile b/justfile new file mode 100644 index 0000000..1d42fb0 --- /dev/null +++ b/justfile @@ -0,0 +1,27 @@ +set shell := ["bash", "-euo", "pipefail", "-c"] + +default: ci + +setup: + bash scripts/dev.sh setup + +lint: + bash scripts/dev.sh lint + +test: + bash scripts/dev.sh test + +typecheck: + bash scripts/dev.sh client-typecheck + +build: + bash scripts/dev.sh client-build + +run: + bash scripts/dev.sh dev + +docs: + @echo "See AGENTS.md and documentation/development.md." + +ci: + bash scripts/dev.sh check