…layer (LLP 0174)
The release-battery smoke asserted that attaching with no ai-gateway
capability always prints a message naming @hypaware/ai-gateway, with a
client.attach span carrying error_kind=cap_missing.
LLP 0174 #detection deliberately split that single failure into two
states, and #585 (f17b091) implemented it: when the requested name is
contributed by a bundled plugin, the capability being absent means that
adapter is not enabled, not that the install lacks a gateway, so the gate
now reports 'the claude adapter is not enabled on this install' with
error_kind=adapter_not_enabled. Only a name no plugin contributes keeps
the old cap_missing wording. The behaviour is the settled design and is
covered by test/core/attach-enablement-state.test.js; the smoke's
expectation was the stale half.
Update the smoke to assert both halves of the split rather than just
retargeting the old one: `claude` takes the adapter_not_enabled path and
must name the adapter to enable, and a new dispatch of an uncontributed
name proves the cap_missing wording and span are still reachable.
Fixes #652
The release-battery smoke
client_attach_idempotentfails onorigin/masterand passes at1fbfa0d(v1.19.0). This updates the smoke, which had gone stale against a deliberate, documented design change.Bisect
First bad commit:
f17b091"Manual attach prompts to enable the client adapter (LLP 0174/0178) (#585)".Found with
git bisect runover1fbfa0d..7116f95in a clean detached worktree, usingnpm run smoke -- client_attach_idempotentas the test (FAIL in output = bad). Four steps:92f1ec7is the LLP-only half of the same work (design doc accepted, no code), which is why it is good and its code siblingf17b091is bad.Diagnosis
The smoke's kernel #2 activates no plugins at all, then runs
hyp attach --client claudeand asserts the resulting stderr names@hypaware/ai-gateway, with aclient.attachspan carryingerror_kind=cap_missing.f17b091rewrote exactly that gate insrc/core/commands/clients.js. The!ctx.capabilities.has('hypaware.ai-gateway')check still fires first and still exits 1; what changed is that it now resolves why the capability is absent before choosing the wording:claude) ->error: the claude adapter is not enabled on this install; enable it with 'hyp init', or add @hypaware/claude to <config> and run 'hyp daemon restart', then re-run attach,error_kind=adapter_not_enabledattach requires the @hypaware/ai-gateway plugin to be installed and activated,error_kind=cap_missingSo the precedence did not move. The gate is the same gate, in the same place; only its message and
error_kindbecame state-dependent.Code or smoke?
The smoke. This is not a judgement call once the docs are read:
llp/0174-attach-prompts-to-enable.design.mdis Active, and its#detectionsection settles the three-state split, naming the capability gate as one of the two failure sites that must report the enablement layer. Its#summaryquotes the pre-change message verbatim as one of the two failure modes it exists to fix.llp/0178-attach-prompts-to-enable.plan.mdT3 spells out the new message string, theadapter_not_enablederror kind, and specifies the test case "zero gateway-using plugins active (cap_missingpath lands onnot_enabled)" - i.e. precisely the situation the smoke constructs.test/core/attach-enablement-state.test.jsalready asserts both halves (capability gate: a catalog-known client reports not_enabled, not cap_missingandcapability gate: a name no plugin contributes keeps the cap_missing wording).Reverting the code would undo an Active LLP and break existing unit tests. The new error is also strictly more useful:
@hypaware/ai-gateway is not activatedis unactionable when the real problem is that@hypaware/claudeis not in your config.The change
Only
hypaware-core/smoke/flows/client_attach_idempotent.js. Rather than just retargeting the stale assertion, the smoke now covers both halves of the split, so the smoke tier proves the branch and not only one leg of it:--client claudewith no gateway: exit 1, stderr names the adapter to enable, span haserror_kind=adapter_not_enabled,status=failed,hyp_client=claude.--client frobnicatorwith no gateway: exit 1, stderr still names@hypaware/ai-gateway, span haserror_kind=cap_missing,status=failed,hyp_client=frobnicator.Docblock and
@ref LLP 0174#detection [tests]annotations updated to match. No production code touched.Verification
npm run smoke -- client_attach_idempotent: FAIL before (attach without ai-gateway prints a clear error, observedthe claude adapter is not enabled on this install), ok after.node scripts/run-tests.js: 3574 pass, 0 fail, 1 skipped.npx tsc -p tsconfig.json --noEmit: clean.gateway_claude_captureandcli_bundled_plugins_activated: both ok, so the gate precedence is unshifted.Unrelated, pre-existing (not touched here)
While checking neighbours I found
claude_attach_detachandclient_attach_on_joinalso fail, but they fail identically at1fbfa0d(v1.19.0) with my change stashed, so they are long-standing and predate this bisect window. Neither is in the CLAUDE.md release battery. Worth a separate issue.Fixes #652