release-pipeline-status: an unimplemented adapter primitive is indistinguishable from a broken helper (exit 127), making promote's none branch unreachable #55
Labels
No labels
component:adapters
component:lifecycle
component:qa
component:setup
component:shared
component:worktrees
phase/accepted
phase/backlog
phase/deployed
phase/developing
phase/integrating
phase/planning
phase/qa
phase/requirements
phase/uat
priority:critical
priority:critical
priority:high
priority:high
priority:low
priority:low
priority:medium
priority:medium
type:bug
type:chore
type:docs
type:feature
type:infra
type:tech-debt
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jbr870/devwork-skills#55
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Observation
release-pipeline-status.shcannot distinguish "this project has no CI" from "the helper isbroken", and reports the second shape for the first case.
Hit for real during
/dev:promoteon this repo (2026-08-24, shipping #26 + #50 asdev--v0.1.6):The
tea-cliadapter implements 11 primitives andpipeline_statusis not among them — the filesimply does not exist.
_lib.shinvokes the adapter primitive by path with no existence check, sothe caller gets a shell-level 127 and a message naming an internal helper path, which is not
information the calling skill can act on.
Why it matters
/dev:promoteStep 5 has an explicit, correct branch for exactly this situation:That branch is unreachable on
tea-cli. The skill text anticipates the case; the helper cannotexpress it. An orchestrator following Step 5 literally sees a non-zero exit and should route to
Step 8 — escalate a blocking decision and ship nothing, which is the wrong answer for a repo
that legitimately has no CI. I only proceeded because I could establish "no pipeline exists"
independently (no
.gitea/workflows, no.github/workflows, no such adapter primitive) — i.e. bygoing around the helper, which is not a procedure.
This is the same family as #49 (a gate's failure output must identify the failure) and #54 (a
reader must fail with a diagnosis, not a stack error): an absent capability and a broken call
must not look alike.
Recurrence
Mechanical and permanent for every
tea-cliproject — the primitive is not merely unimplementedfor this repo, it is absent from the adapter.
glab-cli/gh-clishould be checked too: if theyimplement it, the contract is silently adapter-dependent; if they don't, Step 5 is dead code on
three of four adapters.
local-fsis named in the skill text as returningnone, so at least oneadapter is expected to answer.
Hypothesis
pipeline_statusis required or optional. Ifoptional,
_lib.shshould detect the missing primitive and return the contract'snone— anadapter that cannot report pipelines is reporting "no pipeline", which is exactly
none._lib.shmust not exec an adapter primitive by path without checking it exists. Everyprimitive dispatch has this shape, so any unimplemented primitive fails the same opaque way.
none-on-absent is judged too lenient (it could mask a genuinely broken adapter install),the alternative is an explicit
unsupportedstate plus a contract rule that promote treatsunsupportedlikenone— but says so out loud in the Phase Outcome.Suggested lane
Full pipeline — helper behaviour plus a forge-contract change across four adapters.
Filed 2026-08-24 from the
/dev:promoterun that shipped #26 and #50.Scope folded into #47 (2026-08-25,
/dev:requirementssessiondevwork-47-55-pipeline-status-identity).This issue's requirement is now carried by #47's PREQ. The two were folded because they are one defect in
two costumes: the same helper,
release-pipeline-status.sh, returning an answer nobody can attribute —to a commit (#47) or to a stated absence (this issue). Splitting them would have meant changing the same
{state, url}response shape twice.What #47 now carries from here:
_lib.sh's_primdispatch stops invoking an adapter primitive by path without checking it exists —confirmed still true at HEAD:
_prim() { "$ADAPTER_BIN/$1.sh" "${@:2}"; }.already classes
pipeline_statusamong them in §2.2) resolves to a statedunsupported; a requiredop fails loudly with a diagnosis naming the adapter, the primitive and where it was looked for. This is
hypothesis 1 + 2 from this issue, with hypothesis 3's "say it out loud" adopted:
/dev:promoterecordsthe skipped pipeline gate and its reason in the Phase Outcome rather than proceeding silently.
/dev:promoteStep 5's no-CI branch becomes reachable by following the procedure, instead of by anoperator establishing the absence independently.
The adapter census this issue asked for, resolved:
glab-clipipeline_status: nativelocal-fspipeline_status: polyfilltea-cligh-cliSo Step 5 was dead code on two of four adapters, and
gh-clicannot run/dev:promoteat all. Thatsecond finding is filed separately as #69 (sibling of #47) rather than folded, because it is
implementation work rather than honesty work.
Deliberately not done: implementing
pipeline_statusfortea-cli. The Forgejo instance is beingdecommissioned in favour of GitHub, so a primitive written against it is redundant on arrival — and this
issue's own hypothesis is that an adapter which cannot report pipelines is reporting "no pipeline".
Known consequence, recorded as a finding on #47: a
tea-cliproject that does run Gitea Actions would nowget a stated
unsupportedand its real pipelines would go unwatched.This issue is left open and linked to #47 as its folded source; it is not being worked independently.