_prim: a partial project-scope adapter copy is misreported as a capability boundary, silently ungating releases #416

Open
opened 2026-08-26 16:19:23 +00:00 by jbr870 · 0 comments
Owner

Deferred from #47 QA round 1, finding CR-13 (qa-report:v1 domain=code phase=validate, comment 2201). Disposition defer-to-issue, decided by the operator on 2026-08-26.

The gap

_prim in plugin/skills/_shared/procedures/bin/_lib.sh classifies a missing primitive against $ADAPTER_BIN, which is resolved to the first candidate directory that exists (project scope → bundled → user). The classification itself is correct and well-tested (#47 AC-9/AC-10/AC-15); the question is what it is classifying against.

A stale or partial project-scope copy of an adapter — say a vendored glab-cli predating #47, missing pipeline_status.sh — shadows the complete bundled adapter. _prim then finds no script, sees a capability-gated primitive, and reports EXIT_UNSUPPORTED: "this forge cannot do that, and the adapter declares it by shipping no primitive for it."

Why it matters

That is a broken install misread as a capability boundary — precisely the fail-open that #47's gated-but-not-executable branch (AC-15) was written to prevent, arriving by a different route. The consequence is not an error: /dev:promote prints the reassuring skip line and tags ungated, on every release for that project.

The existing defences do not cover it. AC-15 catches a present-but-non-executable primitive. AC-10 catches an absent required primitive. Neither can tell "this adapter genuinely ships no pipeline reporting" from "this copy of the adapter is incomplete", because absence-on-disk is deliberately the declaration (contract §2.2).

Possible directions (not yet decided)

  • Cross-check the resolved $ADAPTER_BIN against the adapter's own declared capabilities:/operations: manifest: a primitive declared non-unsupported but absent on disk is a broken install, whatever scope it resolved from. This also subsumes the manifest-vs-disk parity gap already filed from #47 (see the sibling issue for finding F-PO-47-3-1) — consider folding the two.
  • Or record the resolution scope in the answer/log so a shadowed adapter is at least visible.

Why it was not fixed in #47

It touches adapter resolution, a surface #47 does not otherwise change, and its regression surface is every skill that dispatches a primitive rather than the pipeline path alone.


Filed by QA round 1 on issue #47. Component: component:shared + component:adapters. Related: the sibling issue filed for F-PO-47-3-1 (manifest-vs-disk parity) — these two may be one change.

Deferred from **#47 QA round 1**, finding `CR-13` (`qa-report:v1` domain=code phase=validate, comment 2201). Disposition `defer-to-issue`, decided by the operator on 2026-08-26. ## The gap `_prim` in `plugin/skills/_shared/procedures/bin/_lib.sh` classifies a missing primitive against `$ADAPTER_BIN`, which is resolved to the **first candidate directory that exists** (project scope → bundled → user). The classification itself is correct and well-tested (#47 AC-9/AC-10/AC-15); the question is what it is classifying *against*. A **stale or partial project-scope copy** of an adapter — say a vendored `glab-cli` predating #47, missing `pipeline_status.sh` — shadows the complete bundled adapter. `_prim` then finds no script, sees a capability-gated primitive, and reports `EXIT_UNSUPPORTED`: *"this forge cannot do that, and the adapter declares it by shipping no primitive for it."* ## Why it matters That is a **broken install misread as a capability boundary** — precisely the fail-open that #47's gated-but-not-executable branch (AC-15) was written to prevent, arriving by a different route. The consequence is not an error: `/dev:promote` prints the reassuring skip line and **tags ungated**, on every release for that project. The existing defences do not cover it. AC-15 catches a present-but-non-executable primitive. AC-10 catches an absent *required* primitive. Neither can tell "this adapter genuinely ships no pipeline reporting" from "this copy of the adapter is incomplete", because absence-on-disk is deliberately the declaration (contract §2.2). ## Possible directions (not yet decided) - Cross-check the resolved `$ADAPTER_BIN` against the adapter's own declared `capabilities:`/`operations:` manifest: a primitive declared non-`unsupported` but absent on disk is a broken install, whatever scope it resolved from. This also subsumes the manifest-vs-disk parity gap already filed from #47 (see the sibling issue for finding `F-PO-47-3-1`) — consider folding the two. - Or record the resolution scope in the answer/log so a shadowed adapter is at least visible. ## Why it was not fixed in #47 It touches adapter **resolution**, a surface #47 does not otherwise change, and its regression surface is every skill that dispatches a primitive rather than the pipeline path alone. --- *Filed by QA round 1 on issue #47. Component: `component:shared` + `component:adapters`. Related: the sibling issue filed for `F-PO-47-3-1` (manifest-vs-disk parity) — these two may be one change.*
Sign in to join this conversation.
No description provided.