132d9eca
Governance: close three gaps in the exposure model
a73x 2026-08-11 18:07
Commit message
docs/superpowers/specs/2026-08-09-repo-governance-design.md
| Old | New | ||
|---|---|---|---|
| @@ -237,11 +237,30 @@ is an access decision, resolved by the same first-match-wins evaluation as any | |||
| 237 | other — including `-` to deny it back. `listed` is an **option**, not a rule, | 237 | other — including `-` to deny it back. `listed` is an **option**, not a rule, |
| 238 | because advertising is a display concern rather than an access one; this is the | 238 | because advertising is a display concern rather than an access one; this is the |
| 239 | `option` line gitolite already has, so it is stolen rather than invented. | 239 | `option` line gitolite already has, so it is stolen rather than invented. |
| 240 | `listed` implies nothing about readability: a repo listed but not | 240 | Three consequences that are easy to get wrong, and each of which an implementer |
| 241 | `R = @anonymous` appears only to viewers who can read it. | 241 | would otherwise have to guess: |
| 242 | 242 | ||
| 243 | `@anonymous` must never satisfy a write grant. `RW = @anonymous` is a config | 243 | **`option listed = yes` requires `R = @anonymous`, and is a config error |
| 244 | error and is rejected by push validation, not silently ignored. | 244 | without it.** The tempting reading — "listed, but only to viewers who can read |
| 245 | it" — is meaningless here: web UI authentication is explicitly out of scope | ||
| 246 | below, so HTTP has no identity and there is no authenticated web viewer to show | ||
| 247 | it to. Listing a repo nobody may read would advertise a name that 404s. Reject | ||
| 248 | the pair at push validation rather than rendering it. | ||
| 249 | |||
| 250 | **`@anonymous` never satisfies a write grant.** `RW = @anonymous` is a config | ||
| 251 | error, rejected by push validation, not silently ignored. | ||
| 252 | |||
| 253 | **The inverted default applies only where governance is in force.** A server | ||
| 254 | with no `settings.git` keeps today's behaviour exactly — that is already an | ||
| 255 | asserted requirement (`tests/governance_test.rs`, the `ungoverned` harness) and | ||
| 256 | flipping the default globally would silently hide every repository on every | ||
| 257 | existing deployment the moment it upgraded. The default is a property of the | ||
| 258 | governed world, not of the binary. | ||
| 259 | |||
| 260 | **Release downloads follow the repo's anonymous read grant.** They are served | ||
| 261 | over HTTP from the repo's gitdir, so `R = @anonymous` governs them for the same | ||
| 262 | reason it governs a clone. Publishing and deleting stay `RW+` and remain | ||
| 263 | SSH-only. | ||
| 245 | 264 | ||
| 246 | ### Bootstrap, corrected | 265 | ### Bootstrap, corrected |
| 247 | 266 | ||