---
name: platform-ci-cd
description: THIS repo's CI/CD instance — gate topology, exact commands, file map, platform-specific gotchas. Use when running/debugging the platform gate, merging a PR, touching lefthook/pr-gate/main-gate/cpu-limit, or asking "why is MY push slow / blocked". Generic doctrine (cache, containment, deflake) lives in global ci-cd-expert — this skill holds only what is platform-specific.
---

# platform-ci-cd — this repo's CI instance

Audience: AI coding agents first. Doctrine (WHY + portable primitives) = global `ci-cd-expert` skill — point there, NEVER re-inline. This file = platform's concrete instance: names, paths, commands, local gotchas.

MUST follow `/home/user/Projects/0 DOCS/GIT_FATIGUE.md` §12. Valid current-tree receipt/log = proof; NEVER rerun broad checks. MUST read §12 before adding or changing gates/hooks/CI. User surface MUST be only `Preview ready` or `Needs product decision`.

## Topology (instance)

- Authoritative gate: `.github/workflows/pr-gate.yml`, `pull_request`, runner labels `[self-hosted, linux, x64, platform-gate]`, runner install `/opt/actions-runner-platform`, 90min timeout, runs `pnpm gate`.
- `main-gate.yml` + `delivery.yml` = delivery ONLY (changesets publish → GHP `npm.pkg.github.com` scope `@platform-modules`, PRIVATE; `deploy-mod-cms` verifies `HEAD == TESTED_SHA`, wrangler deploy, `arm-after-deploy.mjs`). NEVER treat main-gate as safety net.
- Publication only via delivery controller; `node scripts/safe-merge.mjs <PR#>` is controller-owned legacy primitive. Agents MUST NOT run raw `gh pr merge`, `git push`, or `git merge`.
- Local pre-push (`lefthook.yml`): ≤10s handoff only; NEVER typecheck/build/test/e2e. Designated executor owns one receipt-backed gate.
- Versions: all `@platform-modules/*` stay `0.x` until deliberate public release — any `1.0.0` = defect.

## Commands

- Heavy build/test/turbo raw invocations are deny-gated. Valid receipt → read it. No receipt → designated executor invokes canonical gate once; NEVER use workstation `# raw-ok` bypass.
- Gate chain (root package.json): `gate` = `typecheck && test && test:scripts && verify`; `verify` = `build && node tools/smoke.mjs && node tools/bundle-check.mjs && check:skill-references && check:subpath-exports`.
- Editing `docs/standards/coding-standard.md` → MUST regen: `pnpm build:skill-references`.
- Shared cache: `/var/cache/platform-turbo` (ACL dev↔runner). Aggregate cap: systemd user `build.slice`. Knobs: `scripts/cpu-limit.sh` (BUILD_CPU_RESERVE, BUILD_SCHED_IDLE=0 in CI, VITEST_MAX_FORKS…).

## Pending gate additions (verify merged before relying)

- Branch `feat/gate-hardening` (PR open): `check:registry` + `check:imposition` wired into `verify`; generated exports-walk smoke (all packages, all subpaths); `tools/packaging-conformance.mjs` (§6 packaging law + version<1.0.0); changeset-required step; gitleaks + fork-PR guard in pr-gate.
- Branch `feat/slopgate-enforcement` (PR open): slopgate self-test fixed, project rule pack (host-agnosticism imports, responsive @media ban in ui-*, comments law, cross-package instanceof, `.only`, idempotency-key M3, a11y onClick), wired: lefthook pre-commit staged fast tier + agent edit-hooks + pr-gate changed-files backstop. Config: `.slopgate/config.toml`.
- After merge: update this section — move entries into Topology/Commands, drop branch names.

## Platform-specific gotchas

- **Branch/worktree predates CI stack**: old lefthook runs heavy push gate. Replace hook with ≤10s controller handoff; NEVER rebase solely to recover hook behavior.
- L0 change (`packages/db`, `packages/util`) → `--affected` = near-everything, cold run ~15m legit. Not a cache bug.
- New package ff-merged from worktree → `pnpm install` on main BEFORE push, else gate dies `ERR_MODULE_NOT_FOUND`.
- local-gate/cpu-guard "run-*.scope already loaded" while raw systemd-run works = known local-gate bug; one-off `# raw-ok`, fix belongs in local-gate.
- `apps/consumer` i18n Playwright `integration.spec.ts:15` locale-switch flakes under cold-gate load — pre-existing; fix = await locale flip, do NOT retry-loop the gate.
- Fork-PR RCE: self-hosted runner + `pull_request` — repo MUST NOT go public before fork guard on every job (see pending gate-hardening PR).
- Adding `./subpath` export to a package REQUIRES adding its src entry to that package's `tsup.config.ts` entry list — else export 404s in dist while src-import tests stay GREEN (bit us: PR#84 util/memo). Generated smoke (pending) catches this class.
