Belts as permissions: Time's gates consult the belt ledger instead of a human #92

Open
opened 2026-10-18 01:16:36 +00:00 by teahubxyz · 0 comments
Owner

Depends on #85

Why. Once the dojo grades a seat on an SOP, "may this seat do X unsupervised?" is a test result, not an opinion. Belts stop being decoration and become the permission system; seats domesticate themselves by passing katas, and nobody hand-assigns rights.

Ledger. time/belts.json, committed, written only by the dojo runner (#85) from a passing ladder: {seat: {skill: {belt, run, at, lapsed}}}. Belts are soulbound and monotonic, as in orgchain v1.14: a promotion is a new entry over the old one, never a removal. A failed re-run sets lapsed: true — the belt stays on the record, the permission switches off until the seat passes again. Re-runs every TIME_BELT_REVIEW_DAYS (default 28) or whenever the SOP changes. The operator may grant a belt by a decision logged in docs/decisions.md (the founder's prerogative), and it is marked granted.

Permissions table. time/permissions.json: action → (skill, minimum belt). Starting rules:

  • review.engine: an Approve on a PR under .github/time/ counts in verdict() only from a seat with ≥ brown in review; a lower belt's review is recorded as a COMMENT.
  • review.product: Approve counts from ≥ green in review.
  • plan.queue: queuing cards (Astra) needs ≥ brown in management (the sizing kata).
  • steward.repair: the steward tick (#80) acts only with black in management; otherwise it runs in report-only mode.
  • escalate.tier: the automatic one-tier retry (#78) targets only seats with ≥ green in build.
  • Deterministic jobs (housekeeping, Time's own merges, the governor) need no belt: code, not judgment.

Mechanics. belts.py: belt(seat, skill), allowed(seat, action); verdict(), plan_spec/Astra, the steward and the retry path call allowed(). Enforcement is behind TIME_BELTS=on (default off), so the first ladder run (#85) can grant the initial belts before anything is gated; with it off, allowed() logs what it would have refused. cmd_doctor prints the belt table and which gates are live.

Audit. Every kata run commits its transcript next to the result, so a belt can be contested by re-running the kata; graders are deterministic where possible and never the seat under test. Later: mirror each promotion as an orgchain inscription on the seat's sat (lineage/orgchain v1.14 belts), so the chain certifies what the ledger says.

Tests. A brown-in-review seat's Approve on an engine PR merges; a green one's is recorded as a comment and does not; a lapsed black steward runs report-only; with TIME_BELTS off nothing is refused and the would-have-refused lines appear; a granted belt counts like an earned one.

CHANGELOG line under "### Added". Docs: .agents/skills/belts/SKILL.md, linked from AGENTS.md.

DONE: PR open with the code above, python3 .github/time/test_time.py green including the new checks, CI green

Depends on #85 **Why.** Once the dojo grades a seat on an SOP, "may this seat do X unsupervised?" is a test result, not an opinion. Belts stop being decoration and become the permission system; seats domesticate themselves by passing katas, and nobody hand-assigns rights. **Ledger.** `time/belts.json`, committed, written only by the dojo runner (#85) from a passing ladder: `{seat: {skill: {belt, run, at, lapsed}}}`. Belts are soulbound and monotonic, as in orgchain v1.14: a promotion is a new entry over the old one, never a removal. A failed re-run sets `lapsed: true` — the belt stays on the record, the permission switches off until the seat passes again. Re-runs every `TIME_BELT_REVIEW_DAYS` (default 28) or whenever the SOP changes. The operator may grant a belt by a decision logged in `docs/decisions.md` (the founder's prerogative), and it is marked `granted`. **Permissions table.** `time/permissions.json`: action → (skill, minimum belt). Starting rules: - `review.engine`: an Approve on a PR under `.github/time/` counts in `verdict()` only from a seat with ≥ brown in `review`; a lower belt's review is recorded as a COMMENT. - `review.product`: Approve counts from ≥ green in `review`. - `plan.queue`: queuing cards (Astra) needs ≥ brown in `management` (the sizing kata). - `steward.repair`: the steward tick (#80) acts only with black in `management`; otherwise it runs in report-only mode. - `escalate.tier`: the automatic one-tier retry (#78) targets only seats with ≥ green in `build`. - Deterministic jobs (housekeeping, Time's own merges, the governor) need no belt: code, not judgment. **Mechanics.** `belts.py`: `belt(seat, skill)`, `allowed(seat, action)`; `verdict()`, `plan_spec`/Astra, the steward and the retry path call `allowed()`. Enforcement is behind `TIME_BELTS=on` (default off), so the first ladder run (#85) can grant the initial belts before anything is gated; with it off, `allowed()` logs what it would have refused. `cmd_doctor` prints the belt table and which gates are live. **Audit.** Every kata run commits its transcript next to the result, so a belt can be contested by re-running the kata; graders are deterministic where possible and never the seat under test. Later: mirror each promotion as an orgchain inscription on the seat's sat (`lineage/orgchain` v1.14 belts), so the chain certifies what the ledger says. **Tests.** A brown-in-review seat's Approve on an engine PR merges; a green one's is recorded as a comment and does not; a lapsed black steward runs report-only; with `TIME_BELTS` off nothing is refused and the would-have-refused lines appear; a granted belt counts like an earned one. CHANGELOG line under "### Added". Docs: `.agents/skills/belts/SKILL.md`, linked from AGENTS.md. DONE: PR open with the code above, `python3 .github/time/test_time.py` green including the new checks, CI green
teahubxyz added the queued label 2026-10-18 01:55:39 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: teahubxyz/time#92