Selftest sweep with a real SKIP channel — npm run sweep (T707)
This project has no test framework; the selftest:* smokes ARE the test suite, and the sweep is how
you run all of them before a push. It replaced ~15 lines of bash that lived inside
.github/workflows/ci.yml.
npm run sweep # every selftest:* script, discovered from package.json
npm run sweep -- --security # just the declared security/data-integrity class
npm run sweep -- --only sandbox-deny,queue # a subset, by name without the `selftest:` prefix
npm run sweep -- --list # print what would run, run nothingSleep prevention (kgmzx). On macOS the sweep re-runs itself under /usr/bin/caffeinate -i -s (printing one line saying so), marked by CYBERINE_SWEEP_CAFFEINATED=1 so it happens once; SWEEP_NO_CAFFEINATE=1 opts out and --list never re-execs. Each smoke is timed on both the wall clock and the monotonic clock, which does not advance while the Mac sleeps. When the wall clock ran at least 10 s past the awake time, the smoke's line (FAIL <name> ... -- possible idle sleep: ... or a note: under a PASS) says how long the machine slept, the summary repeats it, and a full run's stamp records it under notes next to caffeinated: true|false. Measured 2026-09-25: a sweep that slept mid-run failed 6 smokes that all passed alone.
Known limitations: the note detects real sleep only. CPU throttling while the machine stays awake advances both clocks, so a throttled smoke that times out still reads as an ordinary failure; re-run it alone. caffeinate -s holds the system awake only on AC power.
Read the LAST line, not just the exit code. The sweep classifies each smoke on its exit code and the three counts add up to the discovered count:
| exit code | meaning |
|---|---|
0 | PASS — the smoke ran its assertions and they held |
78 | SKIP — the smoke ran NOTHING (see scripts/selftestSkip.ts); not a pass under any reading |
| anything else | FAIL |
Why the code exists: before T707 both CI jobs treated exit 0 as the only success signal, and the
selftests job printed all N selftests passed using the DISCOVERED count. A smoke that printed
SKIP: ... and exited 0 was therefore reported inside the same green number as one that ran fifteen
assertions — CI run 33106474716 skipped the entire host-sandbox regression class (sandbox-deny,
sandbox-devnull, codeexec-bash-jobs) and still went green. The standing "N/N green" precondition for
pushing to main was a claim nobody had verified.
The sweep fails when any smoke fails, AND when the observed skip set differs — in either direction —
from expectedSkips[<platform>] in scripts/selftest-manifest.json. Both platform lists ship EMPTY:
every skip the 2026-08-29 audit found is now either executable (CI installs bubblewrap, so the
sandbox smokes run a real bubblewrap arm) or a bug to fix. An entry that no longer skips is drift
too, and is reported as such, so the file cannot become a graveyard of stale excuses.
Extend recipe — a smoke that genuinely cannot run somewhere: import skipSelftest from
scripts/selftestSkip.ts and call it with a reason naming what is missing; do NOT return or
process.exit(0). If the skip is unavoidable on a platform, add the smoke's bare name (no
selftest: prefix) to that platform's array in scripts/selftest-manifest.json in the same commit,
with the reason in the commit message. A smoke that skips only SOME of its scenarios still exits 0
and reports the partial skip in its own summary line — the sweep's unit is the script, not the
assertion.
Registry-leak guard (k1ejt, scripts/registryLeakGuard.mjs): the sweep snapshots the real
Cyberine registry ($CYBERINE_HOME/runs, default ~/.cyberine/runs — the same env-var resolution
cyberine agents uses) before running any smoke and again after the whole run, and fails when a new
record appears — a smoke wrote a fixture run into the operator's real registry instead of an
isolated CYBERINE_HOME of its own. The failure names the new record ids and points at
cyberine index-prune --fixtures --dry to see which ones look like fixtures. Since kvxvw a new
record whose cwd is an existing directory outside this repo and outside every tmp root is a
concurrent run in another project: the sweep prints it as a registry note and does not count it.
Known limitation: this is a snapshot diff, not a lock — a genuine cyberine serve daemon or another
terminal's cyberine run whose cwd is THIS repo (or a tmp dir) still registers as growth while the
(multi-minute) sweep runs; it is a leak DETECTOR for the sweep's own smokes, not exclusive access to
the registry.
Known limitations and deferred work: the sweep runs the smokes SERIALLY through npm run, so it
carries one npm start-up per smoke (~13 minutes on this machine); since 2026-09-07 it no longer runs
in CI at all — see "Sweep stamp and pre-push gate" below; it does not parallelise, because several
smokes bind fixed ports or a shared throwaway $CYBERINE_HOME. It also cannot detect a smoke that exits 0 while asserting nothing
INTERNALLY — the exit-code protocol only sees whole scripts. scripts/kg4yr-sandbox-symlink-smoke.ts
and scripts/hl-t693-opencode-auth-gate-smoke.ts print their own passed / failed / skipped counts
for that reason, and a new smoke with per-scenario skips should do the same.
Live-provider refusal is a SKIP, not a FAIL (kqm7s, 2026-09-03). Observed live: this repo's own
DEEPSEEK_API_KEY ran out of balance mid-session, and the next sweep went from 172/0 to a hard FAIL
with 6 red checks — every one of them just HTTP 402 {"error":{"message":"Insufficient Balance"}}
from the provider, not a code regression. A smoke that makes a real network call to a live provider
must tell "the account cannot serve a request right now" apart from "the code broke a contract the
smoke exists to guard" — classifyProviderRefusal in scripts/selftestSkip.ts is that
classifier:
| provider status | meaning | classification |
|---|---|---|
402 Payment Required | insufficient balance | SKIP (exit 78) |
401 Unauthorized | key invalid or revoked | SKIP (exit 78) |
403 Forbidden | key not authorized for this resource/model | SKIP (exit 78) |
429 Too Many Requests | quota or rate limit exhausted | SKIP (exit 78) |
400 Bad Request (malformed body, wrong tool_choice, ...) | genuine contract violation | FAIL |
200 with a missing/wrong field (e.g. no reasoning_content, wrong finish_reason) | genuine contract violation | FAIL |
| any other status (5xx, ...) | not classified as a refusal | FAIL |
Only the four "account cannot serve requests" statuses above skip; everything else — including a
400 and a 200 with the wrong shape — still fails. Widening this to "any non-200 is a skip" would
turn a false red into a false green (a real regression sailing through as "unrunnable environment"),
which is strictly worse than the false-red bug this classifier fixes. scripts/t692-smoke.ts
section E is the reference implementation: DEEPSEEK_API_KEY set but refused → exits 78 via
skipSelftest; DEEPSEEK_API_KEY unset entirely → the existing (unrelated) "expected in CI" partial
skip, exit 0, no manifest entry needed. Extend recipe — a new live-provider smoke: call
classifyProviderRefusal(status, body) on every response from the live call; if it returns
non-null AND nothing earlier in the file has already failed, call skipSelftest with the reason —
never call it after a real assertion has already gone red, or a mid-run credit depletion would mask
that failure. A smoke that starts exiting 78 for this reason needs a scripts/selftest-manifest.json
expectedSkips[<platform>] entry (see the Extend recipe two paragraphs up) naming the account-state
fact, not a platform limitation — remove it the moment the account is funded again, or
staleExpectations will flag it as drift.
Adapter liveness — is it FUNDED, not just keyed (--liveness, kwrp9)
cyberine doctor answers "is a key present". It never answered "is that key's account funded", and neither did the fleet TUI's overview, which listed an adapter whenever its key existed and printed...
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...