Skip to content

ci(spoke): tinyland.repo.json + lanes.json + spoke-ci.yml@v3.1.0 wiring (TIN-3914) — DO NOT MERGE before the jesssullivan-blog-nix ARS is applied - #267

Draft
Jesssullivan wants to merge 2 commits into
mainfrom
jess/tin-3914-spoke-ci-wiring
Draft

Jesssullivan wants to merge 2 commits into
mainfrom
jess/tin-3914-spoke-ci-wiring

Conversation

@Jesssullivan

Copy link
Copy Markdown
Owner

DO NOT MERGE before Jesssullivan/jesssullivan-infra applies a jesssullivan-blog-nix ARC scale set serving the jesssullivan-nix label (tofu/stacks/arc-runners/jesssullivan.tfvars). Until that apply lands, every job in the new workflow queues with nowhere to run. This is wiring, not adoption.

This repo had zero ci-templates adoption: no tinyland.repo.json, no .github/lanes.json, and not one uses: tinyland-inc/* across the ten workflow files. It is outside every ci-templates oracle's reach by non-adoption, not by failure.

Additive by construction

.github/workflows/ci.yml is untouched. substrate-boundary, bazel-remote-gates, and build-and-test remain exactly where they are, so required checks and the exact-source proofs that cloudflare-pages-production-v2.yml and github-pages-rollback-v2.yml consume (for (const requiredName of ["build-and-test", "bazel-remote-gates"])) are unchanged. The new workflow is named Spoke CI (TIN-3914), deliberately not CI, so it does not enter the production workflow's workflow_run: workflows: ['CI'] lane.

scripts/test-workflow-authority.mjs — not edited, and here is why

The generic loop (lines 292-310) applies three rules to every file in .github/workflows/. The new file passes all three as written, so the test needed no extension:

Rule Applies? Result
hasPrTrigger && /secrets\.|github\.token|GITHUB_TOKEN/ PR trigger: yes File contains none of the three strings. Pass.
hasManualCarrier && hasAuthority No workflow_dispatch: Not reached. (statuses: write is not in the authority set anyway.)
every non-./ uses: must end in 40 hex one uses: This is the load-bearing one. The rule does not exempt reusable workflows, so spoke-ci.yml@v3.1.0 would fail it. Pinned instead at @d8d178c022a0f84853d53a2c8fe0fc90115f0949 # v3.1.0 — the capture group is [^\s#]+, so it stops before the comment and the SHA validates.

Verified by porting the loop to stdlib Python and running it over all 11 workflow files: 0 failures. ruby ci-templates/scripts/lint-runs-on.rb --root . goes 19 -> 20 runs-on checked with FAIL unchanged at 17, which is the positive proof that jesssullivan-nix is an accepted capability label. no-hosted-runners.rb stays at 23 labels; this PR adds none.

Deliberate deviations from the gftb-site exemplar

  • No secrets: inherit. gftb-site inherits. This lane carries a pull_request trigger, and this repo's standing contract is that a PR-triggered lane reaches no credential. spoke-ci declares one optional secret (ATTIC_TOKEN), and the cache-backed path reads the shared Bazel cache without uploading, so it does not need one. Note the authority test's credential rule keys on the literal secrets., which secrets: inherit would slip past — this follows the rule's intent, not its letter. Revisit only behind a same-repo-only guard.
  • heavy_runner_class: jesssullivan-nix. The template default sends bazel-graph to tinyland-nix-heavy, which serves no repo in this forge scope. Same org-tenancy rationale gftb-site uses.
  • cache_backed_targets overridden. The template default names //:sveltekit_types and //:svelte_check_test. Neither target exists in this repo. Replaced with //:node_modules //:sveltekit_check //:sveltekit_vite_build_smoke from BUILD.bazel.
  • playwright_enabled left at false. The kvm_runner_class job would need a KVM-capable class that is not anchored here.

Manifest and lanes

schema_version: 1. Not a style choice: spoke-ci@v3.1.0 routes through repo-manifest-validate@v3, and the v3 tag still points at d8d178c (2026-08-19), which predates ci-templates d321dbd's v2 schema dispatch. A v2 manifest would fail the gate that this PR is wiring up.

Both files were validated against the vendored ci-templates copies at v3.1.0 (schemas/tinyland-repo-manifest.schema.json, schemas/lanes.schema.json) using that repo's own scripts/manifest-schema-validate.py — the same stdlib validator the composite action falls back to. Both pass. The validator was negative-tested first (hosted runner_class, unknown lane key, bad target class, bad spoke-name case, bad trigger — all correctly rejected), so the greens are not vacuous.

Two honesty notes on the manifest:

  • contracts.nix: "none" — this repo has no flake.nix. tinyland-inc/account-controller sets the same precedent rather than naming a file that is absent.
  • scaffold_tag is omitted. This repo was not spawned from site.scaffold, and the field is optional.

lanes.json carries three lanes named for the check/test/e2e authority this repo already has. The lane schema has additionalProperties: false and no command field, so the mapping to remote:check / remote:test / remote:e2e lives in each lane's free-form extra object. spoke-ci does not read extra; it is the reviewable record of what each lane stands for, not a dispatch. defaults.runner_class: jesssullivan-nix satisfies the vendored runnerClass pattern ^[a-z0-9][a-z0-9-]*-(nix|nix-heavy|nix-kvm|nix-gpu|docker|dind)$. (site.scaffold's docs/ copy of that schema still carries an older hard enum that would reject it — a third fork of the org schema, noted, not touched here.)

Blockers this PR does not fix

Beyond the ARS, spoke-ci@v3.1.0 runs nix develop --command just setup / just build / just check and nix develop --command bazelisk mod graph. The just recipes all exist. flake.nix does not. Every nix develop step will fail once runners exist. lanes-load also falls back to nix develop when the host python lacks jsonschema, and hard-exits 2 when there is no flake.nix either. A flake.nix is a prerequisite for this lane going green and is not in scope here.

Merge order with #264

Written to merge cleanly with #264, which also edits this register. Proven with git merge-tree --write-tree against refs/pull/264/head: conflict-free. #264 inserts a table row after the CI proof row and a bullet at the end of Build, Test, And Deploy; this PR appends a row at the end of the table and a bullet inside the Cross-Repo Delivery Ownership list, so no hunk contexts overlap. Whichever lands second should trim the overlap: #264's paragraph says adoption "first needs ... tinyland.repo.json, and .github/lanes.json", which this PR supplies.

Not run (host rule: this seat is teletype-only)

npm/node/bazel were not run. //:workflow_authority_tests is reasoned about by reading, and by the stdlib port of its generic loop described above — deferred: needs CI-capable seat for the real run. Same for anything requiring nix.

…TIN-3914)

Adopts the org spoke CI contract this repo has had zero adoption of: no
tinyland.repo.json, no lanes.json, and not one `uses: tinyland-inc/*`
reference across the ten workflow files.

Additive only. `.github/workflows/ci.yml` is untouched, so substrate-boundary,
bazel-remote-gates, and build-and-test remain the required checks and the
exact-source proofs that production and rollback consume are unchanged.

- tinyland.repo.json: schema_version 1 (v1 is what spoke-ci@v3.1.0's
  repo-manifest-validate gate validates against), modeled on gftb-site's
  manifest. `contracts.nix: none` because this repo has no flake.nix, matching
  the account-controller precedent rather than claiming a file that is absent.
  `scaffold_tag` is omitted: this repo was not spawned from site.scaffold.
  Validated against ci-templates@v3.1.0 schemas/tinyland-repo-manifest.schema.json
  with that repo's own scripts/manifest-schema-validate.py.

- .github/lanes.json: three lanes named for the check/test/e2e authority this
  repo already has, each recording the npm script it stands for under `extra`
  (spoke-ci does not read `extra`; the lane schema has no command field, so
  this is the reviewable mapping, not a dispatch). `defaults.runner_class` is
  jesssullivan-nix, which satisfies the vendored runnerClass pattern.
  Validated against ci-templates@v3.1.0 schemas/lanes.schema.json.

- .github/workflows/spoke-ci.yml: calls the reusable workflow pinned at the
  v3.1.0 tag's commit d8d178c, not the tag name, because
  scripts/test-workflow-authority.mjs requires every non-local `uses:` in this
  directory to resolve to a 40-hex commit and applies that rule to reusable
  workflows too. That test needed no change: the new file passes its generic
  loop as written. heavy_runner_class and cache_backed_targets override
  template defaults that name a runner pool and two Bazel targets which do not
  exist here. No `secrets: inherit`, diverging from the gftb-site exemplar,
  because this lane carries a pull_request trigger.

DO NOT MERGE before Jesssullivan/jesssullivan-infra applies a
jesssullivan-blog-nix ARC scale set serving the jesssullivan-nix label. Until
then every job in the new workflow queues with nowhere to run.
…s); honest nix contract

The jesssullivan-blog-nix scale set registers runs-on label tinyland-nix --
the overlay runner-taxonomy validator rejects owner-namespaced labels, and
the k8s ARS name is a separate field from the label. Pointing spoke-ci at a
label no listener serves would queue forever. Also stop declaring
contracts.nix none while the wired workflow runs nix develop.
@Jesssullivan

Copy link
Copy Markdown
Owner Author

Blocker from the convergence synthesis fixed at HEAD: default_runner_class/heavy_runner_class repointed jesssullivan-nixtinyland-nix (the label the infra #96 anchor actually registers; the overlay taxonomy validator rejects owner-namespaced labels), and contracts.nix no longer claims none while spoke-ci hard-runs nix develop. Still DO NOT MERGE until: (1) infra #96 is applied and the tinyland-nix listener provably serves this repo; (2) a flake.nix exists here (spoke-ci's nix develop steps fail without one — next-wave item 3).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant