make help, and make ground — one way in, and a list of the rest
Some checks failed
ci / check (push) Failing after 4s

Tier S (utility inside a boundary; chaos d8=5, no override). Provenance in
this message per InnerLoop §Loop tiers.

The maintainer asked how to start the UI. The answer was a five-flag
cb-play invocation nobody could be expected to remember, in a Makefile
whose own header calls itself "one command surface" -- a surface you have
to read the source of is not one.

  make ground                      # play, recording a trial
  make ground PLAYERS=2 SLUG=darvo-confusion
  make trials                      # read the notes back

`ground` timestamps the trial name so two sessions in one day cannot
overwrite each other's notes, and keeps the date prefix because
tools/trials.py reads the age from there.

`make` with no target now lists targets instead of running the heaviest
thing in the file. It extracts the `## ` comments that were already the
convention -- ten of them existed and NOTHING HAD EVER RENDERED THEM.

Which is how the first run found a real defect: `## run all GROUND
scenarios through cb-sim` sat above `dep-weight:`, 167 lines from the
`sim:` it describes. A doc comment nothing reads rots, and this one had --
same family as the message that sat unread for four days and the ten
rulings nobody collected, in a third medium. Moved to `sim`, and
`dep-weight` given its own.

Documented the targets a person reaches for (coverage, status, all,
self-tests, sim, design, difficulty, trials) and listed the undocumented
instruments compactly, so nothing in the file is invisible.

Verified end to end rather than by inspection: `make ground` served a
page (200), a note posted through it (303), and `make trials` reported it
bound to its position.

loop-lint clean, check clean, self-tests 0 failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-06 14:53:07 +02:00
parent de2a2431e2
commit ac57ce2011

View file

@ -21,10 +21,22 @@ export PATH := $(dir $(CARGO)):$(PATH)
PY := python3
TOOLS := $(REPO)/tools
# `make` with no target lists what there is, rather than running the
# heaviest thing in the file. The Makefile's own header calls itself "one
# command surface" -- a surface you have to read the source of is not one.
.DEFAULT_GOAL := help
# A trial's name. Timestamped so two sessions on one day cannot overwrite
# each other's notes, and prefixed with the date because `tools/trials.py`
# reads the age from there (falling back to mtime).
TRIAL_NAME := $(shell date +%Y-%m-%d-%H%M)$(if $(SLUG),-$(SLUG),)
PLAYERS ?= 3
PORT ?= 0
# Every cargo recipe runs at the repo root; the shell does not persist cd.
IN_REPO := cd $(REPO) &&
.PHONY: check test sim bench bench-test coverage dep-weight cost cost-test cost-pin cost-budget shape-budget cost-mix loop-lint self-tests env-test task-done status facts-check facts-gen mutation-check size-metrics runtime-metrics build-time am6 am7 am8 edition-check replay-test loc play gate-review all \
.PHONY: help ground check test sim bench bench-test coverage dep-weight cost cost-test cost-pin cost-budget shape-budget cost-mix loop-lint self-tests env-test task-done status facts-check facts-gen mutation-check size-metrics runtime-metrics build-time am6 am7 am8 edition-check replay-test loc play gate-review all \
design difficulty trials
# `design`, `difficulty` and `trials` were added by CB-WP-0022, CB-WP-0025
# and CB-WP-0027 and none was declared here. Only `trials` revealed it, by
@ -32,6 +44,38 @@ IN_REPO := cd $(REPO) &&
# ran nothing. The other two work by luck: no file happens to share their
# name. A target that is a command, not a file, belongs on this line.
## list every target, with what it does
## `make help` is also what bare `make` runs.
help:
@echo "clay-borg — make <target> (bare \`make\` shows this)"
@echo
@awk '/^## /{ sub(/^## /,""); d[++n]=$$0; next } \
/^[a-zA-Z][a-zA-Z0-9_-]*:/{ \
if (n) { split($$1,a,":"); printf " %-16s %s\n", a[1], d[1]; \
for (i=2;i<=n;i++) printf " %-16s %s\n", "", d[i]; print "" } \
n=0; next } \
{ n=0 }' $(MAKEFILE_LIST)
@echo " Variables: PLAYERS=3 PORT=0 SLUG=<name> ARGS=\"...\""
@echo
@echo " Undocumented (instruments and gate internals):"
@awk '/^## /{ d=1; next } \
/^[a-zA-Z][a-zA-Z0-9_-]*:/{ if (!d) { split($$1,a,":"); print a[1] } d=0; next } \
{ d=0 }' $(MAKEFILE_LIST) | sort -u | tr "\n" " " | fold -s -w 66 | sed "s/^/ /"
@echo
## play GROUND in a browser, recording a trial (the usual way in)
## Opens a URL; game on the left, notes on the right. Everything you
## type in the notes panel is bound to the position you typed it at.
## `make ground PLAYERS=2 SLUG=darvo-confusion`
## Read the notes back afterwards with `make trials`.
ground:
@mkdir -p $(REPO)/trials
@echo " trial: trials/$(TRIAL_NAME).md (notes) + .yaml (the game)"
$(IN_REPO) $(CARGO) run -q -p cb-play -- \
--players $(PLAYERS) --serve $(PORT) \
--record trials/$(TRIAL_NAME).yaml \
--trial trials/$(TRIAL_NAME).md $(ARGS)
## fmt + clippy (deny warnings) + HashMap deny-lint
check:
$(IN_REPO) $(CARGO) fmt --all --check
@ -50,10 +94,11 @@ gate-review:
test:
$(IN_REPO) $(CARGO) test --workspace
## run all GROUND scenarios through cb-sim
## AM-4 dependency weight: third-party lines behind each budget
dep-weight:
$(PY) $(TOOLS)/dep-weight.py
## AM-1 rule coverage: which GROUND rules a scenario exercises
coverage:
$(PY) $(TOOLS)/rule-coverage.py
@ -117,6 +162,7 @@ loop-lint:
$(PY) $(TOOLS)/loop-lint.py
# Positive control for every reporting tool, per InnerLoop v1.1 Step 5.
## positive control for every reporting tool
self-tests:
$(PY) $(TOOLS)/cb-cost.py --self-test
$(PY) $(TOOLS)/loop-lint.py --self-test
@ -171,12 +217,14 @@ facts-gen:
# CB-WP-0027 T04: what the players said, and where. Surfacing is the
# deliverable -- a commentary feature nobody can read is this project's
# signature failure in a new medium (ADR-0014 D6).
## what the players said while playing, and where
trials:
@$(PY) $(TOOLS)/trials.py
# CB-WP-0025 T06: the difficulty table (specs/RetrospectiveAnalysis.md §4).
# Winnable fraction from the solver plus a PLURAL policy panel -- a single
# policy's win rate may not be reported as a difficulty (§4.1).
## winnable fraction + a plural policy panel (never one bot's win rate)
difficulty:
@cargo run --release -q -p games-ground --example difficulty
@ -184,11 +232,13 @@ difficulty:
# specs/GroundRules.md. Shows the QUEUE by default; the log of closed
# findings is a line, not a listing, because a default view that mixes
# them loses the queue property (ADR-0012 D5).
## the design-finding register: what is open, and what lacks a reproduction
design:
@$(PY) $(TOOLS)/design.py
# T03: one-shot orientation — workplans, next task, spend, fast gates.
# Cheap by design: no build. Start a session with this instead of grepping.
## one-shot orientation: workplans, next task, spend, fast gates
status:
@$(PY) $(TOOLS)/status.py
@ -218,6 +268,7 @@ cost-mix: cost-test
cost-pin: cost-test
$(PY) $(TOOLS)/cb-cost.py --pin fc76445 --composition --by-task
## run all GROUND scenarios through cb-sim
sim:
$(IN_REPO) $(CARGO) run -q -p cb-sim -- $(REPO)/scenarios/ground/*.yaml
@ -237,4 +288,5 @@ loc:
printf '%-28s %s\n' $$d "$$(find $$d/src -name '*.rs' | xargs cat | grep -vcE '^\s*(//|$$)')"; \
done
## every gate, in order. The one CI would run.
all: check test sim coverage size-metrics runtime-metrics am6 am7 am8 edition-check replay-test dep-weight self-tests env-test facts-check loop-lint bench-test