Skip to content

release skill: two states the lane cannot resolve without a remote, and an ancestry-blind baseline #570

Description

@SUaDtL

Deferred findings from the third blind agent-judgment exercise of the portable /ca:release skill (#563). The run found no HIGHs; these are the MEDIUM/LOW remainder, filed rather than fixed because each edit to the skill invalidates the recorded agent-judgment proof (.codearbiter/reports/agent-lane-proof.json) and forces a re-run. The three findings that were pure prose gaps were fixed in the same batch; these four need design decisions, not wording.

1. release_nondraft has no local source, and gh cannot distinguish why it failed

Its only stated origin is gh release view. In a consumer with no remote:

$ gh release view v1.3.0 --json url,isDraft,tagName
no git remotes found
exit=1

gh reports "no remote configured" and "no such release" through the same non-zero exit. Harmless on a fresh tag — tag_exists=false short-circuits before the argument is read — but it matters precisely in the resume_publish / already_published branch, which is where the answer decides whether an already-published release gets republished.

The skill now STOPs on an ambiguous gh failure rather than passing a guess, which closes the unsafe path. What it does not do is give a local-only consumer any way to proceed. Open question: is a --assume-unpublished style explicit operator assertion warranted, or is STOP the correct terminal state?

2. --latest is unevaluable without a remote

The rule is: assert --latest only when the row declares latest-eligible: true and this tag is newest across every declared series (compare against gh release list). gh release list fails identically with no remote. So a row can declare eligibility while the second condition cannot be evaluated, and the skill gives no instruction for that state.

3. last_tag_select is ancestry-blind — documented, reproducible, and cheap to close

Reproduced trivially in the exercise: v1.3.0 was tagged on one branch; a sibling branch that diverged at v1.2.3 and does not contain v1.3.0 still resolved LAST_TAG=v1.3.0, because resolution is by highest semver across the series with no reachability check.

$ git merge-base --is-ancestor v1.3.0 HEAD
→ LAST_TAG IS NOT an ancestor of HEAD

The window came out right (the branches diverge), but the base version did not: that branch would derive 1.4.0 instead of 1.3.0. The skill documents this accurately as a known residual. The point of this item is that it costs exactly one git merge-base --is-ancestor to detect, and the lane never spends it.

4. The back-fill lane has no unattended path, and names its target from a module constant

Two facets of the same lane:

  • backfill-detect proposes a row named app, from _BACKFILL_DEFAULT_TARGET in _releaselib.py — not from anything in the consumer repo (the exercise's fixture named itself scratch-consumer in package.json). The operator is asked to confirm verbatim a name derived from a module constant.
  • Back-fill step 2 requires explicit confirmation before writing, so the lane cannot complete unattended by construction. That is correct and deliberate for an interactive operator, but it means there is no automation path at all through first-time target declaration.

Whether to derive the default name from the manifest, and whether an unattended path should exist, are both design calls.

Low

The prose's literal TAG_PREFIX=$(python3 … tag-prefix $TARGET) form has no exit-code check; on failure it captures empty and the lane derives a base version of 0.0.0 — silent, plausible-looking, wrong. Caveated by the exercising agent itself: a compliant agent STOPs earlier, so this is an exposure in the written form rather than a reachable defect.


Full run record, including the five scenarios and what each proved: .codearbiter/reports/agent-lane-proof.json.

Metadata

Metadata

Assignees

No one assigned

    Labels

    decisionNeeds a user decision / ADR (not a straight fix)sev:medTribunal/triage: medium severity

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions