Promotion check — npm run promote:check (2026-10-02)
Operator decision 2026-10-02: no customers yet and still in the dev phase, so there is no automatic
CI. .github/workflows/ci.yml and .githooks/pre-push were deleted, the homelab self-hosted runner
was stopped, and nothing runs after a change, a commit or a push. What the CI ran is now a local
promotion check that the operator triggers when a promotion to main is near, through the
/ci-policy skill:
npm run promote:check # all three jobs against HEAD
npm run promote:check -- --ref <sha> # another commit
npm run promote:check -- --jobs gate,docs # skip the site job
npm run promote:check -- --sweep # then the full selftest sweep (clean tree at that commit)
npm run promote:check -- --cleanup # remove the generated workspace right after
node scripts/promote-check.mjs list # this host's runs, result, workspace present or cleaned
node scripts/promote-check.mjs cleanup <runId> # remove ONLY what that run generatedIt checks the commit out into .claude/worktrees/promote-<runId>/ (branch worktree/promote-<runId>),
runs npm ci, then the gate job (typecheck, lint:gate, selftest:gate-list-drift,
selftest:claude-md-drift, scripts/plugin-check.sh, selftest:dep-audit), the docs job
(docs:catalog:check, docs:plugin-cheatsheet:check) and the site job (its own npm ci, both doc
syncs, site typecheck and lint, the eslint-config-next guard, the site dependency audit, the design QA
gate that builds the static export). Each job stops at its first failure inside a 10 / 15 / 20 minute
budget; the environment carries CI=true, CYBERINE_TASK_TRUSTED=false, CYBERINE_CC_MEMORY=0 and a
fresh temp CYBERINE_HOME. Exit 0 means every requested step passed.
Every run writes, once, to .local/promote-check/<host>/<runId>/ (runId <YYYYMMDD-HHMMSS>-<sha8>):
run.json (commit, ref, main-checkout HEAD and dirty paths, node/npm/OS versions, the generated paths
and sizes, each step's command, cwd, exit code, signal, timeout flag, timings and log file),
NN-<job>-<step>.log with each step's full output, and summary.txt. cleanup deletes only the
run's worktree, its branch (git branch -d, so only when merged) and its temp CYBERINE_HOME, after
checking them against the run id and run.json; it refuses a worktree with a modified tracked file
and a run still marked running, records what it did in cleanup-<stamp>.json, and never touches the
logs, run.json, configs, stamps or other runs.
Known limitations and deferred work. It checks the committed tree, never uncommitted edits. It
runs whatever node is on PATH (the runner used node 22; a different major is flagged in the output and
in run.json, not refused). The dependency audits need the npm registry. Nothing runs it
automatically, by design; a broken main surfaces at the next promotion check the operator asks for.
The browser-dependent design checks (layout audit, 60fps, reduced-motion) stay UNVERIFIED, as they were
on the runner.
Security-gate drift check — npm run selftest:gate-list-drift (T707, retargeted 2026-09-07)
The security/data-integrity smoke list froze on 2026-08-22 in two hand-maintained copies (the CI gate loop and the git-workflow rule's precondition 3), and ten security smokes shipped afterwards...
Sweep stamp — .local/selftest-stamp/ (2026-09-07; push gate removed 2026-09-30, hook removed 2026-10-02)
A full npm run sweep (no --only / --security) records its verdict in .local/selftest-stamp/<host>/<HEAD sha>.json. From 2026-09-07 a tracked pre-push hook refused a push to main without an ok:...