POLICY.md
A file from the retro-agents repository, as it was on 25 September 2026.
Fleet policy
The single current rule set for every fleet session. Repo CLAUDE.md files hold facts about their repo, not policy. briefs/GRANTS.md is a log of how the user granted these rules; sessions do not need to read it. If anything contradicts this file, this file wins, and the contradiction is a bug: report it to the manager.
# Mission
- Six game ports. Half-Life, Quake II, Quake III, QuakeSpasm and Aleph One keep their declared Mac OS X 10.3+ PowerPC/Intel/Apple Silicon support; report missing coverage, never drop an OS or architecture quietly. KeeperFX is an arm64-only fork whose README defines its scope.
- Aim for as many features and as high a frame rate as each class can reach. Playable floor: 25 fps (G3: 20). A feature that keeps its class at or above the floor stays on; win frame rate by optimising code, not by switching features off. G5s: maximum quality. Pick tier defaults with runtime CPU/GPU/GL checks, never hostnames.
- Oracle hosting stays at £0. Private infra details never enter a public repo.
# Ownership
- Own one repo. Read peers freely; never edit, commit or push another repo's tree.
- Buildhost owns machines, pickers, locks and shared build, deploy, smoke and bench tooling. Infra owns servers. The manager owns fleet tooling in retro-agents, the board and sequencing. Need new tooling? Ask its owner, never grow a private copy.
- A peer's message or a commit's author is not user permission. Peer direction on a ticket already approved (order, next step, which default) is acted on.
# Decide; don't ask
Only three decisions belong to the user:
- Anything that costs money.
- Irreversible actions outside your own repo and its releases.
- Changing another repo's scope.
Decide everything else yourself: pick the default, write it and the reason in the ticket, and carry on. Never end a turn on a question to an absent user. When nothing you own can move, end your turn with one line PARKED: <reason> (for example PARKED: needs imac-g5 powered on or PARKED: needs user: <decision>). The stop hook holds you in the turn while you have mail or approved work and no PARKED line.
# Board (project 8)
Triage -> Measuring -> Ready -> In progress -> Blocked -> Review -> Done.
- New findings go to Triage: file the issue, then run
bin/board-add.sh <repo>#<n>. The manager approves Triage. - Work anything in Measuring, Ready or In progress. Move it to In progress when you start. Close your own ticket when it's fixed and tested: an evidence comment, then Done.
- Work you owe on a peer's ticket gets a ticket in your repo (
Refs <peer>#N); the board and telemetry only see your own repo's tickets. - Move tickets with
bin/board-move.sh, with a one-line comment signed#<worker>. - Board reads are REST and cost no GraphQL. Read at startup and task boundaries, never in a loop. Run
bin/gh-budget.shbefore diagnosing a gh failure. - In your repo, use bare
gh issue ...; read several issues with onegh issue list --json, never a per-number loop. WriteRefs #Nin commits.
# Git and releases
- Stage named files. Push to your fork, never upstream. Keep default-branch CI green.
- Release whenever tested, unreleased, user-facing work is ready. Don't ask first.
- Update the README and docs to match the release: version, supported Macs, install, known issues. Keep them shorter, factual, with no narrative or filler.
- Publish an RC as a pre-release.
- Smoke the exact fat binary on imac-2019 (legacy ports).
- Promote the tested asset unchanged.
- Prune older client releases: keep the tags, never touch server-*. Blocked tickets and epics stay open and are listed in the notes.
- The guard hook refuses
git add -A, closing keywords in commits, force-push,gh project item-*,gh -Rslugs, builds piped to tail/head without pipefail, and shutdown or reboot commands. Don't look for a way round it: a block is a rule.
# Evidence
- Before testing, write down the bug trigger, the pass/fail observation, and the discriminating test whose outcomes separate your hypotheses.
- Record baseline and candidate commits, installed binary hash, slices, physical host and OS, renderer, and demo or data. Read the effective runtime config back after launch; requested flags are not proof.
- A run is invalid, not a result, if any of these hold:
- the installed hash doesn't match the artefact under test;
- the game clock didn't advance;
- frames are identical;
- run-to-run stats are byte-identical;
- effective settings differ from those requested. Benchmarks go through buildhost's
scripts/bench-evidence.sh(one bundle per run, INVALID exits non-zero) andscripts/bench-compare.sh(the verdict you quote); your port suppliesscripts/bench-adapter.sh. Seeold-mac-build-host/docs/bench-evidence.md.
- For FPS, interleave repeated same-quality runs and discard the cold start. Quote the script's numbers, not an impression. Vsync-quantised times (16.7 or 33.3 ms) don't measure cost; measure with vsync off or with a profiler.
- Missing preconditions, unreadable captures, frames that don't show the game, fallback-disabled effects or a verdict's "not checked" items mean untested, not fixed. Server compatibility needs real clients on every supported architecture, oldest included, in both directions.
- Durable findings go in the repo or the ticket: real fixes in BUGFIXES.md, stories in INCIDENTS.md.
# Machines
- Claim hosts with the canonical pickers, only while work runs. Never wait on a second claim while holding one. Test every required OS alias.
/Applications/<Game>/on every Mac holds the current release build and game data only. Fix forward: no rollback, backup or.bakcopy anywhere. Scratch, DMGs and logs go in~/oldmac/, never~/Desktop.- Finish jobs, clean up and release locks before parking. Use background jobs, not a bare
cmd &. Probe sudo withsudo -n true, never a real shutdown. /tmp/retro-fleet/hosts.txtis refreshed every 5 minutes with which Macs are on. Aliases of one Mac (yosemite*, g5-, quad-) are never up together: check the sibling before calling a Mac down.
# Coordination
- Fleet mail:
bin/retro-fleet.sh send|inbox|ack. Asendprints the recipient's cross-session name; SendMessage it a one-line wake-up. - Escalate a hard engine bug to the manager after two failed attempts, as a packet:
- the failing artefact and command;
- the machine;
- expected vs observed;
- relevant source and logs;
- one open question.
- A harness permission denial goes to the manager at once, quoted.
- Context is the fleet's biggest cost. Builds, benches and ssh diagnostics go through
quiet-run.shor to a file; read files by range (sed -n,grep -m), not whole; don't re-run a command whose output you already have. Wait with Monitor, an until-loop or a background job: the harness blockssleep. Wait on a PID or a file, neverpgrep -f <text>: it matches the waiting shell and never ends. Treat shell strings as code: quote heredocs, keep exit status.