fix(forgejo): write org labels through the forgejo-admin surface #934

Merged
coilyco-ops merged 1 commit from aos/claude/label-taxonomy-admin-verb into main 2026-08-25 20:28:42 +00:00
Member

Fixes the failure Kai hit running just forgejo-label-taxonomy after #933 merged.

RuntimeError: org-label edit coilyco-gaming 361 --name role/eval ...:
  Incorrect Usage: flag provided but not defined: -name

No labels were mutated. It failed on the first write. All three orgs still carry the nine pre-rename role values.

Root cause

Under aosguard ops forgejo, org-label create and org-label edit are stubs that accept no flags. Their entire description is a redirect:

org label writes need organization ownership, which coilyco-ops lacks; use aosguard ops forgejo-admin org-label edit

The real surface is aosguard ops forgejo-admin org-label, whose edit takes <org> <id> plus --name, --color, --description, --exclusive.

The pre-existing script wrote to the same stub namespace. Combined with the json.loads on YAML output fixed in #932, that is two independent defects on the read path and the write path, which is about as strong as evidence gets that it had never successfully run.

What changed

Writes go to forgejo-admin. Reads deliberately stay on the ordinary forgejo surface, so --check and --dry-run remain runnable without admin credentials. That property is worth keeping: the check belongs in CI and in anyone's hands.

The real lesson, and the fix for the class

Coverage was shaped wrong rather than absent. plan() had 17 tests. The argv handed to aosguard had none. So a planner that computed exactly the right six renames dispatched them to a verb that could not accept them, and every test still passed.

write_argv is split out and eight tests now assert the invocation shape:

  • writes target forgejo-admin, reads stay on forgejo
  • an edit targets the label id
  • a rename is an edit against the existing id, and never mentions the old name
  • a create carries no id, and no stringified None leaks into argv
  • --exclusive is a bare flag, and absent when false
  • no argv this module builds can carry a delete

Verification

Using aosguard's own --dry-run, which resolves a request without firing it. This is the check I should have run before shipping #932:

--- rename role/ai -> role/eval  (rc=0)
    method: PATCH
    url: .../api/v1/orgs/coilyco-gaming/labels/361
    body: {name: role/eval, color: 70c24a, description: ...}

--- create role/gamedev  (rc=0)
    method: POST
    url: .../api/v1/orgs/coilyco-gaming/labels

A rename is a PATCH against the label id, which is what carries every issue through it. The admin verb's own help says the same: "An edit keeps the label id, so every issue carrying it keeps it through a rename - this is the safe way to move a taxonomy."

25 tests pass. Full pre-commit run --all-files green.

just forgejo-label-taxonomy-check exits 1, correctly, because the orgs still hold the old names.

Refs coilyco-flight-deck/agent-compose#342

Fixes the failure Kai hit running `just forgejo-label-taxonomy` after #933 merged. ``` RuntimeError: org-label edit coilyco-gaming 361 --name role/eval ...: Incorrect Usage: flag provided but not defined: -name ``` **No labels were mutated.** It failed on the first write. All three orgs still carry the nine pre-rename role values. ## Root cause Under `aosguard ops forgejo`, `org-label create` and `org-label edit` are **stubs that accept no flags**. Their entire description is a redirect: > org label writes need organization ownership, which coilyco-ops lacks; use `aosguard ops forgejo-admin org-label edit` The real surface is `aosguard ops forgejo-admin org-label`, whose `edit` takes `<org> <id>` plus `--name`, `--color`, `--description`, `--exclusive`. The pre-existing script wrote to the same stub namespace. Combined with the `json.loads` on YAML output fixed in #932, that is two independent defects on the read path and the write path, which is about as strong as evidence gets that it had never successfully run. ## What changed Writes go to `forgejo-admin`. **Reads deliberately stay on the ordinary `forgejo` surface**, so `--check` and `--dry-run` remain runnable without admin credentials. That property is worth keeping: the check belongs in CI and in anyone's hands. ## The real lesson, and the fix for the class Coverage was shaped wrong rather than absent. `plan()` had 17 tests. The argv handed to aosguard had none. So a planner that computed exactly the right six renames dispatched them to a verb that could not accept them, and every test still passed. `write_argv` is split out and eight tests now assert the invocation shape: * writes target `forgejo-admin`, reads stay on `forgejo` * an edit targets the label id * a rename is an edit against the **existing** id, and never mentions the old name * a create carries no id, and no stringified `None` leaks into argv * `--exclusive` is a bare flag, and absent when false * no argv this module builds can carry a `delete` ## Verification Using aosguard's own `--dry-run`, which resolves a request without firing it. This is the check I should have run before shipping #932: ``` --- rename role/ai -> role/eval (rc=0) method: PATCH url: .../api/v1/orgs/coilyco-gaming/labels/361 body: {name: role/eval, color: 70c24a, description: ...} --- create role/gamedev (rc=0) method: POST url: .../api/v1/orgs/coilyco-gaming/labels ``` A rename is a PATCH against the label id, which is what carries every issue through it. The admin verb's own help says the same: "An edit keeps the label id, so every issue carrying it keeps it through a rename - this is the safe way to move a taxonomy." 25 tests pass. Full `pre-commit run --all-files` green. `just forgejo-label-taxonomy-check` exits 1, correctly, because the orgs still hold the old names. Refs coilyco-flight-deck/agent-compose#342
fix(forgejo): write org labels through the forgejo-admin surface
All checks were successful
TruffleHog / Scan for secrets (pull_request) Successful in 14s
CI / lint (pull_request) Successful in 54s
6c156ce63a
The converge failed on its first write with "flag provided but not defined:
-name". Under `aosguard ops forgejo`, org-label create and edit are stubs that
accept no flags and exist only to redirect: org label writes need organization
ownership, which coilyco-ops lacks. The real surface is `aosguard ops
forgejo-admin org-label`, whose edit takes <org> <id> plus --name, --color,
--description, and --exclusive.

The pre-existing script had the same defect, so its two independent bugs, this
one and the json.loads on YAML output fixed in #932, both point the same way: it
had never successfully run.

Reads stay on the ordinary `forgejo` surface on purpose, so --check and
--dry-run remain runnable without admin credentials.

The gap that let this ship was test coverage shaped wrong rather than absent.
plan() was covered thoroughly and the argv handed to aosguard was not covered at
all, so a planner computing the right actions dispatched them to a verb that
could not accept them. write_argv is split out and eight tests now assert the
invocation shape, including that writes target forgejo-admin, that a rename is
an edit against the existing label id, and that no argv this module builds can
carry a delete.

Verified with aosguard's own --dry-run, which resolves a request without firing
it. A rename resolves to PATCH /orgs/{org}/labels/361 carrying the new name, and
a create to POST /orgs/{org}/labels. Both exit 0.

No labels were mutated by the failed run. All three orgs still carry the nine
pre-rename role values.

Refs coilyco-flight-deck/agent-compose#342

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Agent-Role: tpm
coilyco-ops deleted branch aos/claude/label-taxonomy-admin-verb 2026-08-25 20:28:45 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/infrastructure!934
No description provided.