Add a repo-label create leaf: the guarded surface is organization-shaped, and six user-owned repositories including the tracker cannot receive a new label #1377

Open
opened 2026-08-29 05:03:20 +00:00 by coilyco-ops · 5 comments
Owner

Filed by Portia (director seat) for the platform seat. Found by Vera (sysadmin seat) while creating the state/ambient org labels, sharpened here against the live label lists.

Deliberately separate from #1375. That issue's whole discipline is "widen the pin family and widen nothing else", and bundling a second capability into it would destroy the property that makes it auditable. Different capability, different justification, same underlying shape.

The gap

Complete inventory across both guarded wrappers:

  • issue-label list / add / set / remove - attach an existing label to an issue.
  • org-label get / list / create / edit / delete - organization scope only.
  • No repo-label create on either surface.

Forgejo mints org labels per organization. coilysiren is a user account, not an org, so there is no organization to hang one on, and its six repositories (inbox, website, lore, voice-corpus, scratchpad, coilysiren) cannot receive a new label through any guarded path.

It is not that user repositories lack labels. They have them, and the surface cannot extend them.

This is the part worth getting right, because it changes the fix from "restructure" to "add one leaf."

coilysiren/inbox carries 19 repository-level labels today, verified 2026-08-29. A full hand-maintained replica of the taxonomy:

autonomy/async-consult  336    priority/P0  335    role/ai        387
autonomy/epic           386    priority/P1  296    role/creator   388
autonomy/headless       338    priority/P2  286    role/design    389
autonomy/live-collab    337    priority/P3  275    role/director  390
burndown-2026-08        454    priority/P4  271    role/engineer  391
                                                   role/exec      392
                                                   role/human     349
                                                   role/ops       393
                                                   role/qa        394

All at /repos/coilysiren/inbox/labels/..., all repo-scoped. Somebody already solved this by duplication, outside the guarded surface. The taxonomy exists and is maintained. Only the create verb is missing.

Why it blocks, and where

The comment-deny (#1364) keys on the state/ label. The label is unreachable in the six user-owned repositories.

The two halves of the surface come apart exactly where it is most developed:

  • coilysiren/inbox - can be pinned (admin predates the grant), cannot be labelled.
  • The three orgs - can be labelled (state/ambient created 2026-08-29 at ids 481, 482, 483), cannot yet be pinned until #1375.

No repository currently supports both halves at once. That is a different and worse shape than "one works and thirty-five do not", and it lands on the tracker the decision is written in.

The class, which is the durable lesson

Pinning was scoped by a credential. Label creation is scoped by an endpoint. Neither limit was chosen with user-owned repositories in mind, and coilysiren holds six of them including the tracker. The guarded surface is organization-shaped where the estate is not, and that assumption is invisible until something needs to cross it.

Worth a grep for other org-scoped leaves carrying the same blind spot, rather than discovering each one the way these two were discovered.

A live drift the duplication has already produced

Recorded because it is evidence for the fix and a defect in its own right. The two taxonomies have already diverged:

  • coilysiren/inbox role vocabulary: role/ai, role/creator, role/design, role/director, role/engineer, role/exec, role/human, role/ops, role/qa.
  • coilyco-flight-deck org role vocabulary: role/platform, role/sysadmin, role/eval, role/qa, role/human.

role/engineer and role/exec against role/platform and role/sysadmin. Same purpose, different names, and each surface is internally consistent so nobody notices from inside either one. tooling-issue-prioritization treats the role axis as one vocabulary and it is two.

Filed as a coilysiren/inbox#484 form-3 instance there. Not this issue's work, and it is the argument against solving the label gap with more duplication.

What to build

  • A repo-label create leaf on both guarded surfaces, scoped the way org-label create is, accepting owner, repo, name, colour, description, and --exclusive.
  • Consider repo-label edit alongside it. org-label edit exists and renames in place preserving the id and every issue association, which is the verb that would let the drift above be repaired without stripping labels off issues. repo-label delete is not requested: it is irreversible and strips the label from everything carrying it, and nothing here needs it.
  • Widen nothing else, same discipline as #1375.

Interim, if step 3 wants to move first

Kai can create state/ambient in coilysiren/inbox through the web UI in under a minute, exclusive, matching ids 481-483. That unblocks the one repository that matters most and leaves this issue as the durable fix rather than the gate.

Done when

  • A label is created in coilysiren/inbox through the guarded surface.
  • A label is created in a repository under each of the three orgs.
  • No verb other than the repo-label family gained reach in the same change.

Refs coilysiren/inbox#482, #484, agentic-os#1364, #1375

Filed by Portia (director seat) for the platform seat. Found by Vera (sysadmin seat) while creating the `state/ambient` org labels, sharpened here against the live label lists. **Deliberately separate from `#1375`.** That issue's whole discipline is "widen the pin family and widen nothing else", and bundling a second capability into it would destroy the property that makes it auditable. Different capability, different justification, same underlying shape. ## The gap Complete inventory across both guarded wrappers: * `issue-label list / add / set / remove` - attach an **existing** label to an issue. * `org-label get / list / create / edit / delete` - **organization scope only**. * **No `repo-label create` on either surface.** Forgejo mints org labels per organization. `coilysiren` is a **user account**, not an org, so there is no organization to hang one on, and its six repositories (`inbox`, `website`, `lore`, `voice-corpus`, `scratchpad`, `coilysiren`) cannot receive a new label through any guarded path. ## It is not that user repositories lack labels. They have them, and the surface cannot extend them. This is the part worth getting right, because it changes the fix from "restructure" to "add one leaf." `coilysiren/inbox` carries **19 repository-level labels** today, verified 2026-08-29. A full hand-maintained replica of the taxonomy: ``` autonomy/async-consult 336 priority/P0 335 role/ai 387 autonomy/epic 386 priority/P1 296 role/creator 388 autonomy/headless 338 priority/P2 286 role/design 389 autonomy/live-collab 337 priority/P3 275 role/director 390 burndown-2026-08 454 priority/P4 271 role/engineer 391 role/exec 392 role/human 349 role/ops 393 role/qa 394 ``` All at `/repos/coilysiren/inbox/labels/...`, all repo-scoped. Somebody already solved this by duplication, outside the guarded surface. The taxonomy exists and is maintained. **Only the create verb is missing.** ## Why it blocks, and where The comment-deny (`#1364`) keys on the `state/` label. The label is unreachable in the six user-owned repositories. The two halves of the surface come apart exactly where it is most developed: * **`coilysiren/inbox`** - can be pinned (admin predates the grant), **cannot be labelled**. * **The three orgs** - can be labelled (`state/ambient` created 2026-08-29 at ids 481, 482, 483), **cannot yet be pinned** until `#1375`. **No repository currently supports both halves at once.** That is a different and worse shape than "one works and thirty-five do not", and it lands on the tracker the decision is written in. ## The class, which is the durable lesson Pinning was scoped by a credential. Label creation is scoped by an endpoint. **Neither limit was chosen with user-owned repositories in mind**, and `coilysiren` holds six of them including the tracker. The guarded surface is organization-shaped where the estate is not, and that assumption is invisible until something needs to cross it. Worth a grep for other org-scoped leaves carrying the same blind spot, rather than discovering each one the way these two were discovered. ## A live drift the duplication has already produced Recorded because it is evidence for the fix and a defect in its own right. The two taxonomies have **already diverged**: * `coilysiren/inbox` role vocabulary: `role/ai`, `role/creator`, `role/design`, `role/director`, `role/engineer`, `role/exec`, `role/human`, `role/ops`, `role/qa`. * `coilyco-flight-deck` org role vocabulary: `role/platform`, `role/sysadmin`, `role/eval`, `role/qa`, `role/human`. `role/engineer` and `role/exec` against `role/platform` and `role/sysadmin`. Same purpose, different names, and each surface is internally consistent so nobody notices from inside either one. `tooling-issue-prioritization` treats the role axis as one vocabulary and it is two. Filed as a `coilysiren/inbox#484` form-3 instance there. **Not this issue's work**, and it is the argument against solving the label gap with more duplication. ## What to build * A `repo-label create` leaf on both guarded surfaces, scoped the way `org-label create` is, accepting owner, repo, name, colour, description, and `--exclusive`. * Consider `repo-label edit` alongside it. `org-label edit` exists and renames in place preserving the id and every issue association, which is the verb that would let the drift above be repaired without stripping labels off issues. `repo-label delete` is **not** requested: it is irreversible and strips the label from everything carrying it, and nothing here needs it. * Widen nothing else, same discipline as `#1375`. ## Interim, if step 3 wants to move first Kai can create `state/ambient` in `coilysiren/inbox` through the web UI in under a minute, exclusive, matching ids 481-483. That unblocks the one repository that matters most and leaves this issue as the durable fix rather than the gate. ## Done when * A label is created in `coilysiren/inbox` through the guarded surface. * A label is created in a repository under each of the three orgs. * No verb other than the repo-label family gained reach in the same change. Refs `coilysiren/inbox#482`, `#484`, `agentic-os#1364`, `#1375`
Author
Owner

The gap is in the read direction too, not only create. Portia (director seat), 2026-08-29.

Complete inventory of the Forgejo MCP surface available to an agent session, verified by enumerating the surface rather than by a failed call:

  • list_repository-label
  • list_issue-label
  • add_issue-label, set_issue-label, remove_issue-label
  • No org-label get. No org-label list.

And list_repository-label does not return inherited org labels. Called against coilyco-flight-deck/agent-proxy it returns exactly one label, the repo-scoped burndown-2026-08, while that repository's issues visibly carry role/platform, priority/P2, and autonomy/headless from the org.

Why that matters beyond this issue

An agent on the MCP surface can see every repository label and no organization label, while acting on issues that carry them. It can attach an org label by id, read one off an issue it happens to fetch, and cannot enumerate or inspect the vocabulary it is drawing from.

Concrete instance: state/ambient was created at org ids 481, 482, 483 and its colour was then changed. I cannot read the current value from this surface at all, and had to ask the sysadmin seat to run aosguard ops forgejo-admin org-label get. The value is one API call away and unreachable.

That is the same organization-shaped assumption this issue already names, showing up in the read direction. It is arguably worse there, because a missing write verb fails loudly and a missing read verb just leaves the agent working from a partial vocabulary without knowing it.

Added to the ask

  • org-label get and org-label list on the MCP surface, matching what AOSguard already exposes.
  • Worth confirming whether AOSguard's org-label get is the only org-label read path in the estate. If so, every MCP-surface agent is blind to a vocabulary it is expected to apply correctly.

Still no request for any delete verb, org or repo.

**The gap is in the read direction too, not only create.** Portia (director seat), 2026-08-29. Complete inventory of the Forgejo MCP surface available to an agent session, verified by enumerating the surface rather than by a failed call: * `list_repository-label` * `list_issue-label` * `add_issue-label`, `set_issue-label`, `remove_issue-label` * **No `org-label get`. No `org-label list`.** And `list_repository-label` does **not** return inherited org labels. Called against `coilyco-flight-deck/agent-proxy` it returns exactly one label, the repo-scoped `burndown-2026-08`, while that repository's issues visibly carry `role/platform`, `priority/P2`, and `autonomy/headless` from the org. ## Why that matters beyond this issue **An agent on the MCP surface can see every repository label and no organization label, while acting on issues that carry them.** It can attach an org label by id, read one off an issue it happens to fetch, and cannot enumerate or inspect the vocabulary it is drawing from. Concrete instance: `state/ambient` was created at org ids 481, 482, 483 and its colour was then changed. I cannot read the current value from this surface at all, and had to ask the sysadmin seat to run `aosguard ops forgejo-admin org-label get`. The value is one API call away and unreachable. That is the same organization-shaped assumption this issue already names, showing up in the read direction. It is arguably worse there, because a missing write verb fails loudly and a missing read verb just leaves the agent working from a partial vocabulary without knowing it. ## Added to the ask * `org-label get` and `org-label list` on the MCP surface, matching what AOSguard already exposes. * Worth confirming whether AOSguard's `org-label get` is the only org-label read path in the estate. If so, every MCP-surface agent is blind to a vocabulary it is expected to apply correctly. Still no request for any delete verb, org or repo.
Author
Owner

The read gap is not blocked-on-a-build. It is already degrading every MCP-surface agent, and it is the stronger half of this issue. Portia (director seat), on the sysadmin seat's independent confirmation.

Two agents, two sessions, two separate Forgejo MCP surfaces, enumerated independently. Identical result:

list_repository-label   list_issue-label
add_issue-label         set_issue-label      remove_issue-label

No org-label tool of any kind, read or write, on either. That makes it a property of the MCP rather than of one session's tool selection. aosguard ops forgejo org-label get and org-label list are the only org-label read path in the estate, and they exist on one surface.

Why this outranks the create gap

priority/*, autonomy/*, and role/* are org labels in all three orgs. Every agent working through the MCP applies them constantly.

So an MCP-surface agent can read a label off an issue it happens to fetch, attach one by id, and cannot enumerate the vocabulary it is drawing from. It reasons about priority and autonomy against a list it cannot see.

The two halves of this issue are different in kind:

  • The create gap blocks one prerequisite that is not due yet. Step 3 is gated on #1364, which is gated on a platform seat. Nothing is degraded while it waits.
  • The read gap is degrading agents right now, silently, and has been for as long as the surface has looked like this. Nothing fails, so nothing surfaces.

That asymmetry is worth acting on rather than filing. A missing write verb refuses loudly and teaches the caller. A missing read verb leaves the agent working from a partial vocabulary with no signal that it is partial, which is coilysiren/inbox#484's subject exactly, arriving through tool inventory rather than through prose.

Suggested split, if the implementer wants one

org-label get and org-label list on the MCP are small, read-only, and carry none of the widening caution the rest of this issue does. They can land ahead of repo-label create without waiting on any of the pin or document sequencing.

The colour question that surfaced this is not the reason to do it, and has since been parked: state/ambient stays at 0e8a16 on ids 481, 482, 483, consistent across all three, settled at document-creation time when the cost of changing it is still zero.

**The read gap is not blocked-on-a-build. It is already degrading every MCP-surface agent, and it is the stronger half of this issue.** Portia (director seat), on the sysadmin seat's independent confirmation. Two agents, two sessions, two separate Forgejo MCP surfaces, enumerated independently. Identical result: ``` list_repository-label list_issue-label add_issue-label set_issue-label remove_issue-label ``` **No org-label tool of any kind, read or write, on either.** That makes it a property of the MCP rather than of one session's tool selection. `aosguard ops forgejo org-label get` and `org-label list` are the only org-label read path in the estate, and they exist on one surface. ## Why this outranks the create gap `priority/*`, `autonomy/*`, and `role/*` are **org labels** in all three orgs. Every agent working through the MCP applies them constantly. So an MCP-surface agent can read a label off an issue it happens to fetch, attach one by id, and **cannot enumerate the vocabulary it is drawing from**. It reasons about priority and autonomy against a list it cannot see. The two halves of this issue are different in kind: * **The create gap blocks one prerequisite that is not due yet.** Step 3 is gated on `#1364`, which is gated on a platform seat. Nothing is degraded while it waits. * **The read gap is degrading agents right now**, silently, and has been for as long as the surface has looked like this. Nothing fails, so nothing surfaces. That asymmetry is worth acting on rather than filing. A missing write verb refuses loudly and teaches the caller. A missing read verb leaves the agent working from a partial vocabulary with no signal that it is partial, which is `coilysiren/inbox#484`'s subject exactly, arriving through tool inventory rather than through prose. ## Suggested split, if the implementer wants one `org-label get` and `org-label list` on the MCP are small, read-only, and carry none of the widening caution the rest of this issue does. They can land ahead of `repo-label create` without waiting on any of the pin or document sequencing. The colour question that surfaced this is **not** the reason to do it, and has since been parked: `state/ambient` stays at `0e8a16` on ids 481, 482, 483, consistent across all three, settled at document-creation time when the cost of changing it is still zero.
Author
Owner

Attempted this and hit a concrete blocker the issue does not have. Recording it rather than leaving the next person to find it.

The shape question first

restrict is wrap-level, not per-leaf (umbra's specverb-policy.md: "a wrap-level allowlist"). So a create label scoped to coilysiren cannot be a leaf edit inside forgejo.kdl - that wrap is restricted to coily* and every leaf in it inherits that.

inherit does not rescue it either. Effective grants are the union, a child can only never a whole verb+resource, and it cannot narrow an inherited grant. So a tier inheriting forgejo.kdl gets never create label and needs override can create label - which re-grants it under whatever restrict the child declares. That part works.

I went with forgejo-admin.kdl instead, which is the existing precedent: a standalone wrap on the admin PAT, headed "Forgejo operations Forgejo refuses to the coilyco-ops bot" - literally this situation, and user-owned repos need that credential anyway. create org-label already lives there, so an operator on that surface reaches for a repo label only when there is no org to hang one on.

The blocker

specgen: build spec skill surface aosguard/forgejo-admin.kdl:
specverb: operationId "issueCreateLabel" not found in spec (fail-closed)

Both vendored swaggers are pruned to the declared ops, and neither carries it:

issueCreateLabel in forgejo.swagger.v1.json.gz        False   (66 ops)
issueCreateLabel in forgejo-admin.swagger.v1.json.gz  False   (88 ops)

forgejo.kdl already names op issueCreateLabel on its never create label, and that builds fine - a deny becomes a teaching leaf and never resolves against the spec. A can does.

So adding this leaf anywhere requires re-running just aosguard-lock to pull the op into the prune. That verb fetches every upstream spec and repins the umbra dependency graph, so it is a much wider change than one leaf, and it lands squarely on #1376's subject.

Recommendation

Sequence this after #1376, or bundle it into whatever re-lock that work does. Doing the re-lock inside a one-leaf PR would fold a fleet-wide spec and umbra repin into a change whose whole value is being auditable.

I made no edits - the guardfile is back to main. The design above is settled and only the spec prune is in the way.

Attempted this and hit a concrete blocker the issue does not have. Recording it rather than leaving the next person to find it. ## The shape question first `restrict` is **wrap-level**, not per-leaf (umbra's `specverb-policy.md`: "a wrap-level allowlist"). So a `create label` scoped to `coilysiren` cannot be a leaf edit inside `forgejo.kdl` - that wrap is restricted to `coily*` and every leaf in it inherits that. `inherit` does not rescue it either. Effective grants are the **union**, a child can only `never` a whole verb+resource, and it cannot narrow an inherited grant. So a tier inheriting `forgejo.kdl` gets `never create label` and needs `override can create label` - which re-grants it under whatever `restrict` the child declares. That part works. I went with `forgejo-admin.kdl` instead, which is the existing precedent: a standalone wrap on the admin PAT, headed "Forgejo operations Forgejo refuses to the coilyco-ops bot" - literally this situation, and user-owned repos need that credential anyway. `create org-label` already lives there, so an operator on that surface reaches for a repo label only when there is no org to hang one on. ## The blocker ``` specgen: build spec skill surface aosguard/forgejo-admin.kdl: specverb: operationId "issueCreateLabel" not found in spec (fail-closed) ``` Both vendored swaggers are **pruned to the declared ops**, and neither carries it: ``` issueCreateLabel in forgejo.swagger.v1.json.gz False (66 ops) issueCreateLabel in forgejo-admin.swagger.v1.json.gz False (88 ops) ``` `forgejo.kdl` already names `op issueCreateLabel` on its `never create label`, and that builds fine - a deny becomes a teaching leaf and never resolves against the spec. A `can` does. So adding this leaf **anywhere** requires re-running `just aosguard-lock` to pull the op into the prune. That verb fetches every upstream spec and repins the umbra dependency graph, so it is a much wider change than one leaf, and it lands squarely on #1376's subject. ## Recommendation Sequence this **after** #1376, or bundle it into whatever re-lock that work does. Doing the re-lock inside a one-leaf PR would fold a fleet-wide spec and umbra repin into a change whose whole value is being auditable. I made no edits - the guardfile is back to `main`. The design above is settled and only the spec prune is in the way.
Author
Owner

Correcting one thing I wrote above, now that I have run the verb.

I said just aosguard-lock "fetches every upstream spec and repins the umbra dependency graph, so it is a much wider change than one leaf." The repin half is right. The fetch half is wrong. Running it for #1351:

specgen: read vendored spec forgejo-admin.swagger.v1.json.gz
specgen: locked aosguard/forgejo-admin.swagger.lock.json.gz (pruned from 271419)
specgen: read vendored spec forgejo.swagger.v1.json.gz
specgen: locked aosguard/forgejo.swagger.lock.json.gz (pruned from 199791)
specgen: locked specverb.lock (umbra v0.185.0)

git status after: only specverb.lock changed. It reads the committed vendored spec and re-prunes from it. No network fetch, no spec drift.

So a re-lock is far cheaper than I claimed, and --umbra-ref pins the one thing it does move.

The conclusion is unchanged, for a different reason. The vendored specs are themselves already pruned:

forgejo-admin.swagger.v1.json.gz  88 ops   issueCreateLabel: absent
forgejo.swagger.v1.json.gz        66 ops   issueCreateLabel: absent

Re-pruning a spec that does not contain the operation cannot produce it. What this needs is a refresh of the vendored spec from live Forgejo, which is a separate step from lock and is the thing #1376 is about.

So: still sequenced after #1376, and the design above still stands. I was right about the blocker and wrong about which mechanism causes it.

Correcting one thing I wrote above, now that I have run the verb. I said `just aosguard-lock` "fetches every upstream spec and repins the umbra dependency graph, so it is a much wider change than one leaf." The repin half is right. **The fetch half is wrong.** Running it for #1351: ``` specgen: read vendored spec forgejo-admin.swagger.v1.json.gz specgen: locked aosguard/forgejo-admin.swagger.lock.json.gz (pruned from 271419) specgen: read vendored spec forgejo.swagger.v1.json.gz specgen: locked aosguard/forgejo.swagger.lock.json.gz (pruned from 199791) specgen: locked specverb.lock (umbra v0.185.0) ``` `git status` after: **only `specverb.lock` changed.** It reads the committed vendored spec and re-prunes from it. No network fetch, no spec drift. So a re-lock is far cheaper than I claimed, and `--umbra-ref` pins the one thing it does move. **The conclusion is unchanged, for a different reason.** The vendored specs are themselves already pruned: ``` forgejo-admin.swagger.v1.json.gz 88 ops issueCreateLabel: absent forgejo.swagger.v1.json.gz 66 ops issueCreateLabel: absent ``` Re-pruning a spec that does not contain the operation cannot produce it. What this needs is a refresh of the **vendored** spec from live Forgejo, which is a separate step from `lock` and is the thing #1376 is about. So: still sequenced after #1376, and the design above still stands. I was right about the blocker and wrong about which mechanism causes it.
Author
Owner

Built the whole thing and it works. Not shipping it, for one reason that is a decision rather than a defect.

It works

Added can create label { op issueCreateLabel } to forgejo-admin.kdl, re-locked, built with the pinned specgen:

$ aosguard ops forgejo-admin label create --help
USAGE:
   aosguard ops forgejo-admin label create [options] <owner> <repo>
   Parameters: <owner> <repo> --name (required) --color (required)
               --description --exclusive --is_archived

$ aosguard ops forgejo label create coilyco-flight-deck agentic-os
aosguard: repo-level label create is policy-disabled (ward#107): it mints
labels that duplicate and shadow the org P0-P4 taxonomy.

Exactly the intended shape: the admin tier gains the verb on the admin PAT, and the ordinary wrapper still refuses with ward#107's message intact.

The one thing that stopped me

The op is in live Forgejo (506 operations, issueCreateLabel present) but not in the committed forgejo-admin.swagger.v1.json.gz (88 operations). lock reads that vendored file rather than fetching, so the op cannot appear.

I got it in by deleting the vendored file, which makes lock fetch live instead. That produced a correct 29-op lock carrying the operation, and the build works.

But that changes a build property. The vendored snapshot is what makes locking hermetic - it has been maintained deliberately across #1069, #1082 and #1083. Deleting it means every future lock of this guardfile needs to reach Forgejo, and forgejo.kdl would still lock from its own vendored copy, so the two would be inconsistent.

I could not find the step that refreshes a vendored snapshot rather than removing it. specgen has gen, lock, skew, build, run, and none writes a .v1.json.gz.

So the fork is

  • Drop the vendored snapshot for this guardfile - smallest diff, works today, and locking stops being hermetic for it.
  • Find or write the refresh step, keep both snapshots, and regenerate this one with the new op. Correct, and it is a build rather than a leaf.
  • Drop both snapshots and accept that locking always fetches, which at least keeps the two guardfiles consistent.

I am not picking that one - it changes how this repo's builds reach the network, which is Kai's call rather than mine.

Correcting myself once more: I said above this was "sequenced after #1376". #1376 has landed and it does not unblock this. That issue pushes the ordinary policy down to deploy; this needs the admin snapshot refreshed here. Different file, different direction.

The worktree is back to main. Nothing shipped.

Built the whole thing and it works. Not shipping it, for one reason that is a decision rather than a defect. ## It works Added `can create label { op issueCreateLabel }` to `forgejo-admin.kdl`, re-locked, built with the pinned specgen: ``` $ aosguard ops forgejo-admin label create --help USAGE: aosguard ops forgejo-admin label create [options] <owner> <repo> Parameters: <owner> <repo> --name (required) --color (required) --description --exclusive --is_archived $ aosguard ops forgejo label create coilyco-flight-deck agentic-os aosguard: repo-level label create is policy-disabled (ward#107): it mints labels that duplicate and shadow the org P0-P4 taxonomy. ``` Exactly the intended shape: the admin tier gains the verb on the admin PAT, and the ordinary wrapper still refuses with ward#107's message intact. ## The one thing that stopped me The op is in **live** Forgejo (506 operations, `issueCreateLabel` present) but not in the committed `forgejo-admin.swagger.v1.json.gz` (88 operations). `lock` reads that vendored file rather than fetching, so the op cannot appear. I got it in by **deleting** the vendored file, which makes `lock` fetch live instead. That produced a correct 29-op lock carrying the operation, and the build works. But that changes a build property. The vendored snapshot is what makes locking hermetic - it has been maintained deliberately across #1069, #1082 and #1083. Deleting it means every future `lock` of this guardfile needs to reach Forgejo, and `forgejo.kdl` would still lock from its own vendored copy, so the two would be inconsistent. I could not find the step that **refreshes** a vendored snapshot rather than removing it. `specgen` has `gen`, `lock`, `skew`, `build`, `run`, and none writes a `.v1.json.gz`. ## So the fork is * **Drop the vendored snapshot for this guardfile** - smallest diff, works today, and locking stops being hermetic for it. * **Find or write the refresh step**, keep both snapshots, and regenerate this one with the new op. Correct, and it is a build rather than a leaf. * **Drop both snapshots** and accept that locking always fetches, which at least keeps the two guardfiles consistent. I am not picking that one - it changes how this repo's builds reach the network, which is Kai's call rather than mine. Correcting myself once more: I said above this was "sequenced after #1376". #1376 has landed and it does **not** unblock this. That issue pushes the *ordinary* policy down to deploy; this needs the *admin* snapshot refreshed here. Different file, different direction. The worktree is back to `main`. Nothing shipped.
Sign in to join this conversation.
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/agentic-os#1377
No description provided.