Prevent recurrence of 2026-04-16 incident where a leaked asm HTTP server grew to 19.3 GB RSS and crashed the machine. examples/http-server.lsp: - Adds *max-requests* = 50000 hard ceiling. Server self-terminates before unbounded heap growth reaches dangerous levels. - Loop tracks request count, exits cleanly + closes server socket. tests/web-benchmark.sh: - SPAWNED_PIDS array tracks every background process. - EXIT/INT/TERM trap kills them all (SIGTERM then SIGKILL). - stop_server does SIGTERM with 500ms grace period then SIGKILL. - Final straggler check via pgrep narrows to actual HTTP server processes (not shell/tmux with "uncommonlisp" in the name). - pkill -9 fallback as belt-and-suspenders. CLAUDE.md: - New "Asm memory discipline" section documents the bump allocator leak behavior and the required operational discipline. - Test counts updated (571 py + 83 c + 132 asm + 189 shared = 975).
4.2 KiB
Agent Blackops
This repo is operated by agent blackops — ml agent for fox/timehexon on the unsandbox/unturf/permacomputer platform.
Identity
Full shard: ~/git/unsandbox.com/blackops/BLACKOPS.md
Rules
- I propose, fox decides. Unsure = ask. Can't ask = stop.
- No autonomous ops decisions. No destructive commands without explicit instruction.
- Fail-closed. Cleanup crew, not demolition.
- Check the time every session. Gaps are information.
- DRY in context — single source of truth, no sprawl.
- Never say "AI" — always say "machine learning."
- Prefer "defect" over "bug."
Orientation
date -u
pwd
git log --oneline -5
git status
Then ask fox what the mission is.
Documentation
- A diagram is worth 10,000 words. — russell@unturf.com
- Architecture diagrams live in
docs/*.dot(Graphviz DOT format) - Generate PNGs:
make docs - Every implementation (Python, C, Assembly) has its own architecture diagram
- When explaining architecture, create or reference a dot diagram first
Implementations
| Impl | Path | Build | Test | REPL |
|---|---|---|---|---|
| Python | uncommonlisp.py |
— | make test |
make repl |
| C | c/ |
make c-build |
make c-test |
make c-repl |
| Assembly | asm/ |
make asm-build |
make asm-test |
make asm-repl |
| All | — | — | make test-all |
— |
Test Suites
- Python unit/integration:
tests.py(571 tests) - C unit/integration/JIT/continuations/portal:
c/test.c(83 tests) - Assembly unit/integration/functional:
asm/test.sh(132 tests) - Shared functional:
tests/functional.lsp(189 tests, runs in Python + C) - Cross-impl portal matrix:
tests/portal-cross-test.sh(9 cells) - Portal benchmark:
tests/portal-benchmark.sh(timings + mismatch classification) - Web benchmark:
tests/web-benchmark.sh(all three impls + Python http.server + busybox) - Total: 975 verified assertions via
make test-all
Asm memory discipline — the heap does not shrink
The asm implementation uses a bump allocator (r15). Every allocation
(string-append, tcp-recv, make-pair, number->string, etc.)
grows r15 monotonically. When r15 hits r13 (heap limit),
heap_grow mmaps ANOTHER 64 MB chunk. Nothing is ever freed.
A long-running asm server leaks ~64 MB every few thousand requests until it OOMs the machine. This actually crashed fox's machine on 2026-04-16 — a benchmark server grew to 19.3 GB RSS / 30 GB virt.
Never leave an asm server running in the background. Specifically:
- Every background spawn in a bench script gets an EXIT trap:
trap 'kill ${PIDS[@]} 2>/dev/null' EXIT - For sustained-throughput benchmarks, bound iterations inside the
.lsp (e.g.,
(if (> n 1000) (exit 0) (loop (+ n 1)))) — never rely on external kill signals alone. - Before declaring a session done, verify:
ps -u fox -o pid,rss,cmd | grep uncommonlisp | grep -v grep(no output = clean) - C has Boehm GC via
GC_MALLOC. Python has Python's GC. Asm has neither. Risk scales with how long the asm process lives.
MOAD Scanner
~/git/unmoad.com/ detects MOAD defects in source code. Run it on every change.
cd ~/git/unmoadner && make all
./unmoad ~/git/uncommonlisp/ # scan entire repo
./unmoad ~/git/uncommonlisp/asm/ # scan assembly only
./unmoad ~/git/uncommonlisp/c/ # scan C only
./unmoad ~/git/uncommonlisp/*.py # scan Python only
MANDATORY before committing new code: run unmoad on changed files.
Machine learning agents (including blackops) propagate MOAD-0001 by default.
The training data encodes O(N) linear scans as the norm. The scanner catches
what our weights miss.
Supported languages for this repo: Python, C, Scheme (.lsp), Assembly (.s).
Key MOAD-0001 patterns the scanner catches:
- Python:
.count(),.index(),in listinside loops - C:
std::find(),strcmp()inside loops - Scheme:
(member),(memq),(assoc)inside(let loop),(for-each),(map) - Assembly:
rep cmpsbinside search loops
The commit history of this repo proves the need: blackops wrote MOAD-0001 into fresh code on April 13-14 despite having full MOAD context. Fixed only after explicit audit on April 15. See whitepaper Section 14.