diff --git a/.env.test b/.env.test index f30be14..19cb126 100644 --- a/.env.test +++ b/.env.test @@ -1,8 +1,8 @@ # Host-side watchdog for the normal `just test` CraftOS-PC process. -TRAP_CCLIBS_TEST_TIMEOUT_SECONDS=3 +TRAPOS_TEST_TIMEOUT_SECONDS=3 # Dedicated `just test-timeout` fixture timings. -TRAP_CCLIBS_TEST_TIMEOUT_WATCHDOG_SECONDS=1 +TRAPOS_TEST_TIMEOUT_WATCHDOG_SECONDS=1 # Test placeholders. The real values are generated in `.env` on first `just install`, # or after `just clean` / `just reinstall`. diff --git a/docs/adrs/adr-0005-craftos-pc-harness-and-probes.md b/docs/adrs/adr-0005-craftos-pc-harness-and-probes.md index 3a07432..f1f25ab 100644 --- a/docs/adrs/adr-0005-craftos-pc-harness-and-probes.md +++ b/docs/adrs/adr-0005-craftos-pc-harness-and-probes.md @@ -50,7 +50,7 @@ Extra emulated computers are spawned manually from the CraftOS-PC shell when act ### 3. Headless probes as the canonical hypothesis pattern -Two safe-exec recipes wrap raw `--headless --exec` with `xpcall`, call `os.shutdown()` on success or Lua error, and use `TRAP_CCLIBS_HEADLESS_TIMEOUT_SECONDS` (default `10`) as a host watchdog: +Two safe-exec recipes wrap raw `--headless --exec` with `xpcall`, call `os.shutdown()` on success or Lua error, and use `TRAPOS_HEADLESS_TIMEOUT_SECONDS` (default `10`) as a host watchdog: - `just trapos-exec ''` — probe against the **TrapOS dev environment**. Mounts of `/apis`, `/programs`, `/servers`, `/startup`, `/tests`, and the repo root at `/trapos` are live, so `require('/apis/eventloop')` and friends work against the current branch. Use this when the question involves repo code. diff --git a/docs/adrs/adr-0007-test-framework.md b/docs/adrs/adr-0007-test-framework.md index f62b879..24a043f 100644 --- a/docs/adrs/adr-0007-test-framework.md +++ b/docs/adrs/adr-0007-test-framework.md @@ -50,7 +50,7 @@ Two independent timeout layers, ordered so the finer one fires first. **Layer 1 — `libtest` per-case timeout (primary).** [`apis/libtest.lua`](../../apis/libtest.lua) races each test case against a timer with `parallel.waitForAny(runner, timer)`. The default is `DEFAULT_TIMEOUT_SECONDS = 3`. When the timer wins, the case fails with a distinct message containing the token `libtest timeout` and, in `--verbose`, an extra `TIMEOUT … (libtest)` diagnostic. `--timeout ` overrides the default; `--no-timeout` disables the layer. `runtest` forwards both flags to each case script. This only interrupts cases that yield (the usual hang); a non-yielding CPU loop cannot be preempted in ComputerCraft. -**Layer 2 — shell watchdog (backstop).** The `Justfile` `test:` recipe keeps its `TRAP_CCLIBS_TEST_TIMEOUT_SECONDS` watchdog as an independent double-check. Its default matches the libtest default (`.env.test` ships `3`; the recipe falls back to `3`) so libtest fires first for yielding cases in normal runs and the watchdog only catches what Lua cannot — a non-yielding loop, a wedged libtest, or a deliberately bypassed case. Its SIGTERM message is worded differently from the `libtest timeout` message, so the two layers are never confused. +**Layer 2 — shell watchdog (backstop).** The `Justfile` `test:` recipe keeps its `TRAPOS_TEST_TIMEOUT_SECONDS` watchdog as an independent double-check. Its default matches the libtest default (`.env.test` ships `3`; the recipe falls back to `3`) so libtest fires first for yielding cases in normal runs and the watchdog only catches what Lua cannot — a non-yielding loop, a wedged libtest, or a deliberately bypassed case. Its SIGTERM message is worded differently from the `libtest timeout` message, so the two layers are never confused. ### How to write tests properly @@ -66,7 +66,7 @@ Two independent timeout layers, ordered so the finer one fires first. - `libtest` lives under `/apis` and ships in `trapos-test`, so it can be required consistently in the mounted CraftOS-PC environment. - The `__TRAPOS_TEST_OK__` marker remains the single shell-level success contract and is owned by `runtest`. - A hung case fails in ~3s with a per-case message instead of taking down the whole process anonymously. -- `just test-timeout` is a self-asserting harness regression guard wired into `just ci`. It chains `test-timeout-lua` (Layer 1: libtest cancels the slow case immediately with `--timeout 0`, before the shell backstop) and `test-timeout-shell` (Layer 2: the `TRAP_CCLIBS_TEST_TIMEOUT_WATCHDOG_SECONDS` watchdog, default `1`, kills the slow case with libtest bypassed). Both drive a single `tests/harness/slow-case.lua` fixture; the tight timeouts — not the fixture's sleep length — decide which layer fires, so the harness itself is covered against regressions on every `ci`. +- `just test-timeout` is a self-asserting harness regression guard wired into `just ci`. It chains `test-timeout-lua` (Layer 1: libtest cancels the slow case immediately with `--timeout 0`, before the shell backstop) and `test-timeout-shell` (Layer 2: the `TRAPOS_TEST_TIMEOUT_WATCHDOG_SECONDS` watchdog, default `1`, kills the slow case with libtest bypassed). Both drive a single `tests/harness/slow-case.lua` fixture; the tight timeouts — not the fixture's sleep length — decide which layer fires, so the harness itself is covered against regressions on every `ci`. - `libtest` stays a normal ComputerCraft program: `parallel` and `sleep` are sandbox globals, so the timeout works in CraftOS-PC and in-game alike. - Host-specific concerns remain outside production Lua code. diff --git a/docs/install-craftos-pc.md b/docs/install-craftos-pc.md index 840a9ef..a688b15 100644 --- a/docs/install-craftos-pc.md +++ b/docs/install-craftos-pc.md @@ -90,7 +90,7 @@ On macOS, use the `--rom` form shown above if the command fails with `Could not `just craftos` launches a vanilla CraftOS-PC with no mounts, persistent under `.craftos-vanilla/` (also gitignored). Use it when a probe should not see TrapOS files — for example, to confirm a behavior is upstream rather than TrapOS-specific. -`just trapos-install` exercises the real one-shot installer (`install-trapos.lua`, which bootstraps ccpm then runs `ccpm update` + `ccpm install trapos`) end-to-end on a fresh, ephemeral CraftOS-PC state. Network-dependent and slower than `just test`, so not part of `just ci`. Override the watchdog with `TRAP_CCLIBS_INSTALL_TIMEOUT_SECONDS` (default `60`). +`just trapos-install` exercises the real one-shot installer (`install-trapos.lua`, which bootstraps ccpm then runs `ccpm update` + `ccpm install trapos`) end-to-end on a fresh, ephemeral CraftOS-PC state. Network-dependent and slower than `just test`, so not part of `just ci`. Override the watchdog with `TRAPOS_INSTALL_TIMEOUT_SECONDS` (default `60`). For automated probes, use the safe wrappers. They mount the right environment, shut down the machine after completion or Lua errors, and kill the host process @@ -101,7 +101,7 @@ just trapos-exec 'print("__TRAPOS_TEST_OK__")' just craftos-exec 'print(_HOST)' ``` -Override the watchdog with `TRAP_CCLIBS_HEADLESS_TIMEOUT_SECONDS` (default `10`). +Override the watchdog with `TRAPOS_HEADLESS_TIMEOUT_SECONDS` (default `10`). Pass CraftOS-PC flags directly after `just trapos` or `just craftos` only for manual launches where you want raw emulator control. diff --git a/just/craftos.just b/just/craftos.just index 143f095..6ee96dc 100644 --- a/just/craftos.just +++ b/just/craftos.just @@ -42,9 +42,9 @@ trapos-exec code: #!/usr/bin/env bash set -uo pipefail repo='{{justfile_directory()}}' - timeout_seconds="${TRAP_CCLIBS_HEADLESS_TIMEOUT_SECONDS:-10}" - case "$timeout_seconds" in ''|*[!0-9]*) printf '%s\n' 'TRAP_CCLIBS_HEADLESS_TIMEOUT_SECONDS must be a positive integer' >&2; exit 1 ;; esac - if [ "$timeout_seconds" -lt 1 ]; then printf '%s\n' 'TRAP_CCLIBS_HEADLESS_TIMEOUT_SECONDS must be >= 1' >&2; exit 1; fi + timeout_seconds="${TRAPOS_HEADLESS_TIMEOUT_SECONDS:-10}" + case "$timeout_seconds" in ''|*[!0-9]*) printf '%s\n' 'TRAPOS_HEADLESS_TIMEOUT_SECONDS must be a positive integer' >&2; exit 1 ;; esac + if [ "$timeout_seconds" -lt 1 ]; then printf '%s\n' 'TRAPOS_HEADLESS_TIMEOUT_SECONDS must be >= 1' >&2; exit 1; fi rom_arg=() if [ "$(uname -s)" = "Darwin" ]; then rom_arg=(--rom /Applications/CraftOS-PC.app/Contents/Resources) @@ -113,9 +113,9 @@ craftos-exec code: #!/usr/bin/env bash set -uo pipefail repo='{{justfile_directory()}}' - timeout_seconds="${TRAP_CCLIBS_HEADLESS_TIMEOUT_SECONDS:-10}" - case "$timeout_seconds" in ''|*[!0-9]*) printf '%s\n' 'TRAP_CCLIBS_HEADLESS_TIMEOUT_SECONDS must be a positive integer' >&2; exit 1 ;; esac - if [ "$timeout_seconds" -lt 1 ]; then printf '%s\n' 'TRAP_CCLIBS_HEADLESS_TIMEOUT_SECONDS must be >= 1' >&2; exit 1; fi + timeout_seconds="${TRAPOS_HEADLESS_TIMEOUT_SECONDS:-10}" + case "$timeout_seconds" in ''|*[!0-9]*) printf '%s\n' 'TRAPOS_HEADLESS_TIMEOUT_SECONDS must be a positive integer' >&2; exit 1 ;; esac + if [ "$timeout_seconds" -lt 1 ]; then printf '%s\n' 'TRAPOS_HEADLESS_TIMEOUT_SECONDS must be >= 1' >&2; exit 1; fi rom_arg=() if [ "$(uname -s)" = "Darwin" ]; then rom_arg=(--rom /Applications/CraftOS-PC.app/Contents/Resources) @@ -182,14 +182,14 @@ craftos-exec code: # `ccpm install trapos` itself) on a fresh, ephemeral CraftOS-PC state. # Always installs from the published `master` branch (the only channel). # Network-dependent and slower than `just test`, so not part of `just ci`. -# Override timeout with TRAP_CCLIBS_INSTALL_TIMEOUT_SECONDS (default 60). +# Override timeout with TRAPOS_INSTALL_TIMEOUT_SECONDS (default 60). # See ADR-0005. trapos-install: check-install #!/usr/bin/env bash set -uo pipefail repo='{{justfile_directory()}}' - timeout_seconds="${TRAP_CCLIBS_INSTALL_TIMEOUT_SECONDS:-60}" - case "$timeout_seconds" in ''|*[!0-9]*) printf '%s\n' 'TRAP_CCLIBS_INSTALL_TIMEOUT_SECONDS must be a positive integer' >&2; exit 1 ;; esac + timeout_seconds="${TRAPOS_INSTALL_TIMEOUT_SECONDS:-60}" + case "$timeout_seconds" in ''|*[!0-9]*) printf '%s\n' 'TRAPOS_INSTALL_TIMEOUT_SECONDS must be a positive integer' >&2; exit 1 ;; esac rom_arg=() if [ "$(uname -s)" = "Darwin" ]; then rom_arg=(--rom /Applications/CraftOS-PC.app/Contents/Resources) diff --git a/just/opencode.just b/just/opencode.just index 104faf1..ef44b7c 100644 --- a/just/opencode.just +++ b/just/opencode.just @@ -10,8 +10,8 @@ opencode-serve *args: exit 1 fi export OPENCODE_SERVER_PASSWORD - hostname="${TRAP_CCLIBS_OPENCODE_HOSTNAME:-0.0.0.0}" - port="${TRAP_CCLIBS_OPENCODE_PORT:-4242}" + hostname="${TRAPOS_OPENCODE_HOSTNAME:-0.0.0.0}" + port="${TRAPOS_OPENCODE_PORT:-4242}" exec opencode serve --hostname "$hostname" --port "$port" "$@" # Attach to the local opencode server. Pass a URL first to override the default. @@ -26,7 +26,7 @@ opencode-attach *args: exit 1 fi export OPENCODE_SERVER_PASSWORD - port="${TRAP_CCLIBS_OPENCODE_PORT:-4242}" + port="${TRAPOS_OPENCODE_PORT:-4242}" target="http://127.0.0.1:$port" if [ "${1:-}" != "" ]; then case "$1" in http://*|https://*) target="$1"; shift ;; esac diff --git a/just/test.just b/just/test.just index 832861b..a8830c6 100644 --- a/just/test.just +++ b/just/test.just @@ -24,9 +24,9 @@ _craftos-test *args: pretty=0 has_output=0 - timeout_seconds="${TRAP_CCLIBS_TEST_TIMEOUT_SECONDS:-3}" - case "$timeout_seconds" in ''|*[!0-9]*) printf '%s\n' 'TRAP_CCLIBS_TEST_TIMEOUT_SECONDS must be a positive integer' >&2; exit 1 ;; esac - if [ "$timeout_seconds" -lt 1 ]; then printf '%s\n' 'TRAP_CCLIBS_TEST_TIMEOUT_SECONDS must be >= 1' >&2; exit 1; fi + timeout_seconds="${TRAPOS_TEST_TIMEOUT_SECONDS:-3}" + case "$timeout_seconds" in ''|*[!0-9]*) printf '%s\n' 'TRAPOS_TEST_TIMEOUT_SECONDS must be a positive integer' >&2; exit 1 ;; esac + if [ "$timeout_seconds" -lt 1 ]; then printf '%s\n' 'TRAPOS_TEST_TIMEOUT_SECONDS must be >= 1' >&2; exit 1; fi runtest_args=("$@") for a in "$@"; do @@ -149,11 +149,11 @@ _timeout-fixture script shell_timeout extra_flag expect: check-install # Prove the libtest (Lua) timeout layer: libtest cancels the slow case quickly, # before the shell watchdog backstop can fire. -test-timeout-lua: (_timeout-fixture "/tests/harness/slow-case.lua" "${TRAP_CCLIBS_TEST_TIMEOUT_WATCHDOG_SECONDS:-1}" "'--timeout', '0'," "lua") +test-timeout-lua: (_timeout-fixture "/tests/harness/slow-case.lua" "${TRAPOS_TEST_TIMEOUT_WATCHDOG_SECONDS:-1}" "'--timeout', '0'," "lua") # Prove the shell watchdog backstop: the slow case runs with the libtest timeout # bypassed (--no-timeout), so the shell watchdog kills the whole process. -test-timeout-shell: (_timeout-fixture "/tests/harness/slow-case.lua" "${TRAP_CCLIBS_TEST_TIMEOUT_WATCHDOG_SECONDS:-1}" "'--no-timeout'," "shell") +test-timeout-shell: (_timeout-fixture "/tests/harness/slow-case.lua" "${TRAPOS_TEST_TIMEOUT_WATCHDOG_SECONDS:-1}" "'--no-timeout'," "shell") # Fast regression guard for both timeout layers. Wired into `ci`. test-timeout: test-timeout-lua test-timeout-shell