The trait was named for who lives on a box; what it decides is whether root SSH stays open as the control plane's automation door. Those are different questions, and `dev-server` proved it: an unattended VM-host appliance nobody lives on, correctly class=human because its root door must close. After #76 gave `-server` the job of naming the machine family, that box carried a suffix saying server and a trait saying human. `dev-server --root-door closed` says what is true, once. Unlike #76's role rename this field is read back on live machines, so the compat read is mandatory rather than courteous: one resolver, root_door_of, reads both vocabularies and every consumer goes through it — close-root's gate, apply's note, and bootstrap-tenant's machine-marker guard, which used the presence of `class=` as its "is this a real fleet machine?" test and would otherwise have let a tenant converge clobber a live box. New markers are written as `root-door=` only. Markers carrying both fields in disagreement, or neither, fail closed with a re-run-bootstrap repair. Fixture markers are kept deliberately at the retired spelling (the convention #76's pre-rename-cp fixture established) and pinned at both consumers; deleting the compat arm turns ten checks red. Closes #77 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.6 KiB
Labels
How this repo uses GitHub labels. The taxonomy is shared across the
heavy-duty repos (box, rig, cast) — only the scope: set differs per repo,
because it names this repo's actual surfaces.
State — who is the ball with? (PRs, exactly one)
Every open PR carries exactly one state: label, and it answers the only
question a board scan actually asks: who is this PR waiting on? The states
mirror the review loop this repo runs — PRs open as drafts, three reviewer
bots pick up ready PRs with reviews requested, each round is answered in a
single reply, and a human takes the final review.
| Label | Color | Waiting on | Enters when | Leaves when |
|---|---|---|---|---|
state:building |
#FBCA04 |
the coding agent, still building | PR opened as draft | marked ready + bot reviews requested |
state:bots-reviewing |
#1D76DB |
the reviewer bots to finish the round | ready with reviews requested, or fixes pushed and reviews re-requested | all three bots have reviewed the round |
state:addressing |
#D93F0B |
the coding agent to reply and push fixes | all bots reviewed the round, not all approved | the single round-reply is posted and fixes pushed |
state:needs-human |
#8250DF |
the human reviewer | the human review is requested — by the author when the round passes, or automatically on three formal head-current approvals | merged — or changes requested, which cycles back to state:addressing |
bots-reviewing and addressing are deliberately distinct: staleness in the
first means poke the bots, staleness in the second means the agent dropped
the ball. Collapsing them loses exactly the information a sweep needs.
Cross-cutting (PRs and issues)
| Label | Color | Meaning |
|---|---|---|
stale |
#B60205 |
No activity for 48h. Sweep-managed, never hand-applied. state:building + stale is precisely a forgotten draft. |
blocked |
#6A737D |
Waiting on another PR or issue to land first. Quiet legitimately — the staleness sweep skips it. |
release |
#0E8A16 |
Release flow, versioning, and packaging work. |
Scope — which surface? (PRs and issues, any number)
All scopes share one calm color, #C5DEF5 — scopes locate, states alert.
| Label | Covers |
|---|---|
scope:bootstrap |
commands/bootstrap.sh — hardening a pristine server into a node |
scope:users |
commands/users-* — the root-door model, apply/status, close-root |
scope:runner |
commands/runner-* — GitHub runner install/remove/repoint/status |
scope:coolify |
commands/coolify-* — Coolify and its backup install |
scope:db |
commands/db.sh — dump/restore and the round-trip proof |
scope:installer |
install.sh — how rig itself lands on a machine |
Issue types
bug, enhancement, documentation — issues only. PRs carry their type in
the conventional title (feat:, fix:, docs:), so typing a PR with a label
would just say the same thing twice, drifting apart eventually.
Maintenance
State labels are written by automation, never by hand. Every state above is
derivable from GitHub's own facts — the draft flag, requested reviewers,
review states, push timestamps — so the labels workflow
(.github/workflows/labels.yml) recomputes the
state and reconciles labels statelessly, on a 15-minute cron plus PR events.
A hand-moved label is a lie waiting to happen; the workflow asserts the
effective state instead. scope: labels on PRs are applied from the changed
paths by actions/labeler (.github/labeler.yml);
CONTRIBUTING.md says who sets what.
The same workflow bootstraps the taxonomy: a manual dispatch creates any missing label idempotently. To create them by hand (needs push access):
gh label create "state:building" --color FBCA04 --description "PR is a draft — the coding agent is still building" --force
gh label create "state:bots-reviewing" --color 1D76DB --description "Waiting on the bot reviewers to finish the round" --force
gh label create "state:addressing" --color D93F0B --description "All bots reviewed — coding agent owes the single reply + fixes" --force
gh label create "state:needs-human" --color 8250DF --description "All bots approve — waiting on the human reviewer" --force
gh label create "stale" --color B60205 --description "No activity for 48h — needs a poke (sweep-managed)" --force
gh label create "blocked" --color 6A737D --description "Waiting on another PR or issue to land first" --force
gh label create "release" --color 0E8A16 --description "Release flow and version/packaging work" --force
gh label create "scope:bootstrap" --color C5DEF5 --description "bootstrap — hardening a pristine server into a node" --force
gh label create "scope:users" --color C5DEF5 --description "users-* — root-door model, apply/status, close-root" --force
gh label create "scope:runner" --color C5DEF5 --description "runner-* — GitHub runner lifecycle" --force
gh label create "scope:coolify" --color C5DEF5 --description "coolify-* — Coolify and backup install" --force
gh label create "scope:db" --color C5DEF5 --description "db.sh — dump/restore" --force
gh label create "scope:installer" --color C5DEF5 --description "install.sh — how rig lands on a machine" --force
# delete is not an upsert: a label that is already gone exits non-zero. Swallow
# that, so this block converges on re-run instead of erroring after first success.
for L in duplicate invalid question wontfix "help wanted" "good first issue"; do
gh label delete "$L" --yes 2>/dev/null || true
done