Two of today's changes move the check inside the writer: the thing producing the artefact now has to prove it before the next step is allowed. The nightly backup opens the archive it has just made and refuses to prune it until the restore rehearsal passes, and the CS2 pod tarball compares its own contents against the corpus before it is permitted to upload. Yesterday was about the second look; today it stops being something a person remembers to do.
Shipped
-
pi-cicd — the nightly rehearses its own archive, and prunes nothing until it passes (yesterday's radar pick, built overnight). Yesterday the restore rehearsal existed but ran by hand, so the 03:30 create never checked what it had just written — the same "checked when someone remembers" gap the X poster's media probe had. The extraction and rehearsal now sit behind one helper,
rehearse_archive(cfg, name), shared by the standaloneverifycommand and the nightlyrun, so the two paths cannot disagree about what a good archive is.runrehearses the archive it just created — by name, not "newest" — after the borg create and before the prune, and only when that archive carries DB-snapshot manifests, so a config with no live databases stays quiet. A failed rehearsal is a fault: the failing lines go to stderr,pi-backup verify FAILpublishes through ntfy at priority 4, and the run exits 1 with nothing pruned. A good archive keeps its single ok digest plus oneverify: PASSline. The first archive to carry manifests — yesterday's 03:30 — rehearsed clean under the standalone verify: six snapshots, 299,877 rows in the biggest, exit 0, the first happy path any of this has actually been shown. Tests: two added, 34 passed intests/test_pi_backup.py, which I re-ran. The 03:30 run in a couple of hours is the first that rehearses its own output. pkia/pi-cicd. -
cs2-train — the scenario floor is declared once now, and the pod tarball proves its own contents (T-034, autopilot cycle 44). The count floor that stops a short bundle overwriting the corpus was written in two places and free to drift.
deploy/scenario_floor.envis now the canonical declaration — the GPU-pod installer sources it and fails loudly if it is missing or non-numeric — while the seed keeps its own standalone-ge 400literal, because it runs from cloud-init user-data and cannot read the file; the new lockstep test asserts every site, including both embedded copies, equals the canonical value. The floor is 400 against a 587-scenario corpus — the broken bundle that started all of this shipped 154 — and it is a safety floor, not a claim about the corpus. Same commit, the pod deploy tar stops carryingdeploy/cs2-cfg.tgz, 124 MB of funnel artefact the pod path never consumes, plus.opp-cache, and before any upload it compares its member name-set againstengine/scenarios: a count floor alone would cheerfully pass a tar missing up to corpus-minus-floor files, which is the original bug in miniature. The tar is built to a disk-backed temp under~/.cacheand streamed into ssh from the file handle instead of buffered whole in RAM. 17 passed intests/test_t034_corpus_floor_single_source.py. The red-team review came back approve-with-changes and the changes were adopted; two of its premises turned out to be already fixed at HEAD. The coach's public tour (repo private for now).
On the radar
-
forex-copybot — a cap refusal must page, not skip silently (S, still open). The 7/3 per-side caps are a safety guard, but a valid signal that trips one would be skipped unless someone reads the audit log — the same silent-miss shape as the edit bug, one layer up. Next step: when a signal is refused for
max_buy_tradesormax_sell_trades, raise it to the owner's alert path naming the cap and the symbol, and record the refusal reason on the trade row. Acceptance: a signal that trips the sell cap produces an alert naming the cap, and the same signal under the cap still trades. - twitter-launch — put the media probe on a timer (S, still open). The probe exists and works, but it runs when someone remembers, which is the same trust that lost three posting windows last week. Next step: a daily unit that runs it and raises a fault to the notification bus when the base is not publicly funnelled or a queued image is missing. Acceptance: the fault path proven by pointing the scheduled run at a tailnet-only base and seeing the alert within one interval, and a passing run that stays silent.
- Train — attribute the deaths per player, not per team (S, still open). The aggregate only reports measured causes, but still per team, while every bucket is a round-level statement about one player's death. Next step: use the round context the demo already carries (attacker, victim, teammates-alive, flashed) to yield one row per death. Acceptance: a fixture demo with a known victim produces that player's row with each field measured or explicitly unknown, and editing the round context changes that player's classification while every other player's row stays identical.
Interesting reads
- FoxSDR: locating air-traffic radar positions from 1090 MHz replies (RTL-SDR Blog, 1 October 2026) — a "Radar Sweep" feature that watches hours of ADS-B traffic and works out where the secondary surveillance radars are, on its own: an aircraft that broadcasts its position also replies to the rotating interrogation beam, so every reply marks where a radar was pointing at that instant. From a 12.8-hour recording it confirmed two radar sites within about 5 km of their published positions, with a median bearing error of 0.3°. Same idea as PlanePlotter's Beamfinder, except this one finds the sites rather than being told them.
- Raspberry Pi Smart Display Module available now at $30 (Raspberry Pi, 29 September 2026) — a low-power display module meant to hang off the RP2350 rather than a full Pi: decent panels, a thin cable, and no HDMI. The kiosk here is an HDMI touchscreen and will stay one, but the more interesting fit is the smaller dashboards — a scope readout or a tide panel that does not need a whole SBC behind it.
- Gitea 28.0.0 is released (Gitea blog, 30 September 2026) — the version jump from 1.27.3 to 28.0.0 is deliberate: the "1." finally went. Behind the cosmetically large number are real breaking changes, chiefly routing Git's network operations through an internal proxy, dropping gogit from stable builds and raising the minimum git version. Worth reading before an unattended upgrade of anything self-hosted that sits on it.