Skip to content

Ship & operate

CI Gates — what each check proves

7 min readUpdated Verified against 1560d98 on 2026-09-26

Page actions

ChatGPT and Claude are third-party services. The link gives them this page's public address and a short instruction. This site records nothing.

What each GitHub Actions workflow and job proves before a change can merge or deploy.

The CI gates map On every pull request: web-ci (python, frontend, api-image), scripture-integrity (integrity), version-consistency (versions), security (secrets, static-analysis, deps), pr-hygiene (title), e2e (playwright) and deploy-docs (docs). The integration ruleset requires python, frontend, integrity, secrets and docs; the main ruleset adds versions and static-analysis, strictly. Merges into integration run deploy-staging; merges into main run deploy-production, which waits for the required checks plus playwright on the exact commit. Between merges: the data canary and docs-watch every six hours, uptime (product and wiki) every fifteen minutes, the docs job every night, and on Mondays a full-history secret scan, the external-link check, the sibling docs pins and the page-freshness report. 10 · The CI gates map Every GitHub Actions workflow and job — what it proves, when it runs, and whichchecks a branch ruleset requires before a merge On every pull requestOn a mergeBetween merges web-ci · python — tests, contract, harnessesweb-ci · pythontests, contract, harnessesweb-ci · frontend — the website buildsweb-ci · frontendthe website buildsweb-ci · api-image — the container, over HTTPweb-ci · api-imagethe container, over HTTPintegrity — the pin, 60,658 linesintegritythe pin, 60,658 linesversions — five version strings agreeversionsfive version strings agreesecurity · three jobs — secrets, analysis, depssecurity · three jobssecrets, analysis, depspr-hygiene · title — a conventional titlepr-hygiene · titlea conventional titlee2e · playwright — Ang 712, search, axee2e · playwrightAng 712, search, axedeploy-docs · docs — the wiki, gated like codedeploy-docs · docsthe wiki, gated like code.github/rulesets — what a merge requires.github/rulesetswhat a merge requiresdeploy-staging — integration → stagingdeploy-stagingintegration → stagingdeploy-production — main → production, the tagdeploy-productionmain → production, the tagdeploy-docs: staging and production — the wiki, deployed and smoked by commit, rolled back if notdeploy-docs: staging and productionthe wiki, deployed and smoked by commit, rolled back if notdata-canary · every 6 h — production = the pindata-canary · every 6 hproduction = the pinuptime · every 15 min — health, the App Store URLsuptime · every 15 minhealth, the App Store URLsNightly and weekly — docs nightly · docs-watch · secret scan · links · pins · freshnessNightly and weeklydocs nightly · docs-watch · secret scan · links · pins · freshnessNot here — the scripture gates run in sggs-data; the app’s in gurbani-soul-iosNot herethe scripture gates run in sggs-data; the app’s in gurbani-soul-ios gate: fails the build or the deploycomponent in this projectpin: a reviewed lock fileproven, verified stateexplanationreference: pins, reads or derives from Source of truth: .github/workflows/web-ci.yml ·.github/workflows/deploy-docs.yml · .github/rulesets/integration.json ·.github/rulesets/main.json v1.3.10 · verified 2026-09-27 · d85c2adSri Guru Granth Sahib Ji — Knowledge Base · engineering wiki
Poster 10 — The CI gates map: every workflow and job on a pull request, what a ruleset requires, the deploy chains on a merge, and the schedules between merges · open full size
Workflow · jobProvesNeeds
web-ci · pythonruff clean; server + repo-gate unit tests; the golden contract replayed over HTTP (tools/contract_http.py); contract/openapi.json is current and covers every dispatcher route; /api/health all-true; the shabad-heading regression (api_superset_check); search harnesses; contract does not driftpinned DB
web-ci · frontendAstro builds; pahar vectors pass; report-only: the committed webapp/static equals the build’s text assets byte for byte (scripts/ci/check_static_fresh.py — a warning, not yet a gate)Node 22
scripture-integritydataset pin: dataset.lock.json ↔ contract/_meta.json, and sggs-data publishes that object at the pinned commit; the installed DB passes quick_check with 60,658 lines over Angs 1–1430 (the scripture gates themselves run in sggs-data)pinned DB
version-consistencyall 5 platform version strings unified (the dataset versions in sggs-data; the iOS app keeps its own match); main PRs come from integration/hotfix—
securitygitleaks; bandit; semgrep OSS; actionlint; blocking npm audit --audit-level=high on frontend/ and docs-site/ (job deps)—
pr-hygieneconventional-commit PR title—
e2e · playwrightAng 712 heading smoke, search → panel heading, axe WCAG (serious and critical) on /, /search, /features, /watch and /learn; the Knowledge Base shell on every KB route and the 404 page (frontend/e2e/kb-shell.spec.ts): unique ids, a viewport that still pinch-zooms, and axe in the light and the dark theme against a per-page list of known violations that can only shrink; sideways scroll on a 375 px phone is measured and reported as a warning — the Knowledge Base sets its Latin text in the system font, so that baseline is per platform, enforced on macOS today and on the Linux runners once a Linux baseline is recorded in the spec. One job, two steps: the desktop project (Chromium), then the phone project (iPhone 13, WebKit)serve.py + pinned DB
e2e · kb-lighthouse (report-only, never blocks)Lighthouse with mobile emulation on /search, /reader?ang=1 and /nitnem, served by serve.py; three runs each, no assertions (frontend/.lighthouserc.json); the reports are the kb-lighthouse artifactserve.py + pinned DB, Chrome
web-ci · api-imageDocker image builds; the running container reports the build commit and honours the golden contract over HTTPDocker
deploy-verify (on Vercel deployment_status, previews only)preview /api/health all-true (passes with a notice without the repo-level bypass secret)—
release (manual fallback)idempotent tag + GitHub Release on main; normal releases are cut by deploy-production after a verified deploy—
data-canary (every 6 h, not a PR check)production serves the pinned scripture byte for byte: 500 random lines (/api/lines) and 12 random Angs plus Angs 1, 712, 1430 (/api/ang/N), from the API origin and through the public site’s CDN; the golden contract replays against production; a failure opens or updates one issuepinned DB
deploy-staging · deploy-webthe API functions are generated at the commit from the pinned database (slices proven); after vercel build every function bundles only its entry, the API code and its own database, and no database or API source is in the static outputpinned DB
deploy-staging · verifyevery API function’s /readyz reports this commit and exactly its contexts; no API file is downloadable; the web smoke; every routed context answers through the gateway with its own X-Service; an unknown prefix falls through to all; the whole golden contract passes through the gatewaybypass secret, pinned DB
deploy-docs · docs (required on integration and main)the wiki (docs-site/ over docs/, ADR-0012): pinned sibling docs consistent and installed; tools/docs_check.py (frontmatter, links and anchors, widget fallbacks, Mermaid palette, the scripture-quotation rule, posters, the verified stamps on process/engineering/architecture pages, drift against the code: search modes, verify thresholds, generated pages; the poster legend; the site theme’s brand colours equal docs/brand/tokens.json; the CSP allows inline scripts by hash only); tools/gen_route_table.py --check; scripts/brand/contrast_report.py --check (the committed contrast report equals a regeneration from docs/brand/tokens.json, frontmatter included); tool and plugin unit tests; types (astro check); the site builds with every Mermaid fence rendered to SVG; every page rendered completely; every internal link and fragment in the built HTML resolves; page budgets (JS ≤ 60 KB gz); every inline script allowed by its sha256 in the CSP, no inline handlers (scripts/csp.mjs); Playwright e2e (mocked API) + axe on every built page, served with the production headers and CSP (a blocked script fails the check); Lighthouse (performance ≥ 0.9, accessibility 1, best-practices ≥ 0.95) on five representative pages for a pull request or a push to integration, and on all twenty nightly and on main; every page’s Open Graph card existsNode 22, Chromium
deploy-docs · deploy-staging / deploy-productionthe wiki is deployed only by CI: integration → sggs-docs-staging.vercel.app (refuses to be the project’s first deployment, fails unless its own deployment is a preview); main → record the deployment the domain serves, build, deploy unaliased, smoke by commit, promote to docs.gurbanisoul.com, smoke again, roll back to the recorded deployment if the public smoke fails; every failure opens an issue (scripts/ci/docs_smoke.py, scripts/ci/vercel_api.py). The smoke fails on any redirect. After every staging deploy the live suite runs against staging with the bypass headerdocs Vercel project secrets
deploy-docs · main-guarda push to main whose docs job did not succeed never deploys the wiki; this job opens an issue saying so—
deploy-docs nightly (schedule)the whole docs job re-runs on integration every night, to catch drift from outside the repository (npm, Starlight, sibling docs, the dataset); a red night opens one issue, the next green night closes it—
docs-links (weekly, not a PR check)every external link in docs/ and in the sibling docs the wiki publishes still resolves (lychee, policy in .lychee.toml); a failure opens or updates one issue, never blocks—
uptime (every 15 min, not a PR check)production /api/health all-true; /privacy and /support (the App Store URLs) resolve with their content; a failure opens or updates one issue. Job docs: the wiki’s landing page and /api/health through its rewrite, with no redirect (its own issue)—
docs-watch (every 6 h, not a PR check)docs.gurbanisoul.com serves the commit the last successful deploy-docs run on main shipped (a domain changed outside CI fails it), docs_smoke.py passes, and the live suite (docs-site/e2e-live) passes against the real API: status strip, search, the Ang explorer on Angs 1/712/1256, a line read from the API verifying exact, the API console, ⌘K search, axe as deployed, no CSP errors. One issue, closed when green—
docs-pins (Mondays, not a PR check)when a sibling repository changes a file the wiki publishes, a pull request moves its pin (tools/docs_pins.py; a commit that touched nothing published moves nothing); opened with DOCS_BOT_TOKEN so the required checks run (after a dry-run push proves the token can write), or one issue — naming the cause — when the secret is absent, cannot push, or the pull-request step failsDOCS_BOT_TOKEN (optional)
docs-freshness (Mondays, not a PR check)lists the stamped pages whose cited code (excerpts, linked source files, the posters’ “Source of truth”) changed since their verified stamp, then pages far behind; one issue rewritten weekly, closed when every page is fresh (tools/docs_check.py --freshness)—

The PDF, the corpus rebuild and the scripture gates (reconcile attestation, regroup invariants, scripture guard, editorial ledger, fingerprints) belong to Algorythmos-AI/sggs-data and run in its CI. The iOS app’s gates run in Algorythmos-AI/gurbani-soul-ios.

Run the no-PDF subset locally with make ci.

npm audit has been blocking since the Astro 7 upgrade cleared the advisory backlog (2026-09-20): a new high/critical advisory in frontend/package-lock.json fails security · deps. Fix it with npm audit fix (never --force blind — read the migration notes), rebuild, and re-sync webapp/static/; do not re-add || true.

Deploy pipeline

deploy-production (push to main) waits for the required checks above plus playwright on the exact commit, then deploys API → verifies → builds web unaliased → smoke → promotes → smoke public → tags. Details: runbook: deploy.

Not yet wired (roadmap)

perf (latency budget + Lighthouse on staging) and a load/soak test — nothing yet exercises the request-cost limits this repo now enforces (the /api/verify claim cap, the socket timeout, the bounded worker pool). npm audit is already blocking (see the security row above).