# orchestrator — the CI dispatch Lambda `tinqs/ci-dispatch` (Go, `provided.al2023`, entrypoint `bootstrap`). Receives Gitea push webhooks, fetches each repo's `.gitea/workflows/*.yml`, evaluates triggers (branches, paths, paths-ignore against the pushed changed-files), and spawns one ephemeral EC2 Spot runner per matching workflow — label → instance type via `labelToSpot` (`go/docker/node/godot` → t3.*; `deploy` → ci-exec Lambda; `host` → always-on runner). Also tracks runs in DynamoDB and handles cancel/cleanup events. ## Commit-marker gate (opt-in, 2026-09-22) Add a comment anywhere in the workflow YAML: ```yaml # tinqs-marker: \[(deploy|publish)(-staging)?\] ``` Push events for that workflow then require at least one pushed commit whose message matches the regex (case-insensitive) — otherwise the dispatcher logs `Marker gate: no pushed commit matches …` and spawns **nothing** (no runner, no work; the run Gitea itself created stays queued until some later spawned runner claims it). workflow_dispatch events never reach this gate — the button/CLI always work. Used by `tinqs/ariki-game` `build-sim.yml` (`[deploy]`/`[publish-staging]` → publish the staging sim). Do not remove the gate without asking Ozan. ## Deploying changes ```bash cd orchestrator/dispatch GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bootstrap . zip -q /tmp/dispatch.zip bootstrap aws lambda update-function-code --function-name tinqs-ci-dispatch \ --region eu-west-1 --zip-file fileb:///tmp/dispatch.zip ``` **The zip must contain a file literally named `bootstrap`** (the Lambda handler) — any other name = `Runtime.InvalidEntrypoint` on every webhook. This Lambda serves ALL repos on the instance; keep changes backward-compatible (opt-in conventions only).