fix(rest): restore tiered /menu + make /cartridges & feedback-o-tron E2E truthful#192
Merged
Merged
Conversation
…hful
Resolves the E2E REST-contract drift (deliverable-2). Three groups:
- /menu: the Elixir router returned a flat {count, cartridges} list,
violating openapi.yaml's MenuResponse (tier_teranga/shield/ayo +
summary) — the contract the e2e test AND the mcp-bridge offline menu
already use. Restored tier-grouping via Enum.group_by on each
cartridge's declared tier. Verified against the real manifests:
tier_teranga=10, tier_ayo=115 (so .tier_teranga is non-empty).
- /cartridges: the server (and the mcp-bridge offline fallback) return an
object {count, cartridges:[...]}; the e2e test wrongly did `jq length`
expecting a bare array. Corrected the test to check the actual shape
(.cartridges | length) — no server change, so the mcp-bridge consumer
is unaffected.
- feedback-o-tron: the cartridge FFI (feedback_ffi.zig
boj_cartridge_invoke) is a self-described "Grade D Alpha" stub that
returns {} for the test's tools. Rather than assert an unbuilt feature,
the cycle is guarded behind FEEDBACK_OTRON (default off -> 7 checks
skipped truthfully). Re-enable when the FFI (or a native Elixir
handler) implements open_channel/submit/summary/export/status/
list_channels.
Expected e2e: 0 failures (menu + cartridges pass, feedback skipped).
Note: full e2e runs in CI; elixir/zig/deno are unavailable in the dev
env here, so menu grouping was verified via jq against the manifests and
the test script via bash -n + shellcheck.
https://claude.ai/code/session_019tMcRS1Dm1nWjjYP4WvbJa
🏁 path-claims benchCommit NumbersHost-dependent — compare deltas across commits, not absolute values. |
hyperpolymath
marked this pull request as ready for review
June 4, 2026 12:26
🔍 Hypatia Security ScanFindings: 278 issues detected
View findings[
{
"reason": "Stale AI session file -- delete",
"type": "stale",
"file": "GEMINI.md",
"action": "delete",
"rule_module": "root_hygiene",
"severity": "medium"
},
{
"reason": "Action if: always()\n uses: actions/upload-artifact@ea165 needs attention",
"type": "unpinned_action",
"file": "e2e.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action perpolymath/standards/.github/workflows/governance-reusable.yml@main\n needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in abi-drift.yml",
"type": "missing_timeout_minutes",
"file": "abi-drift.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in codeql.yml",
"type": "missing_timeout_minutes",
"file": "codeql.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in container-publish.yml",
"type": "missing_timeout_minutes",
"file": "container-publish.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
hyperpolymath
added a commit
that referenced
this pull request
Jun 4, 2026
#193) ## What Builds feedback-o-tron *for real* (the follow-up you green-lit), replacing the "Grade D Alpha" stub in `feedback_ffi.zig`'s `boj_cartridge_invoke` with a live, state-machine-backed implementation, and switching the e2e cycle to the cartridge's **actual declared tools**. ## Key insight The stub already dispatched the **correct** `cartridge.json` tool names (`feedback_register_channel/start_collecting/submit/get_stats`) — it just returned `{"status":"stub"}`. The old e2e cycle invoked tools that **never existed** (`open_channel/summary/export/status/list_channels`), which is why it got `{}`. So the fix is: make the FFI real, and point the test at the real tools. ## Changes - **`feedback_ffi.zig`** — `boj_cartridge_invoke` now backs the 4 manifest tools with the existing `fb_*` channel state machine: - `feedback_register_channel` → `fb_register` → `{"slot":N,"channel":C,"state":1}` - `feedback_start_collecting` → `fb_start_collecting` → `{"slot":N,"collecting":true,"state":2}` - `feedback_submit` → `fb_submit` → `{"recorded":true,"slot":N,"feedback_count":K}` - `feedback_get_stats` → `fb_count`/`fb_positive_count`/… → `{"total_feedback":…,"positive":…,…}` - `channel`/`slot`/`sentiment` are read from the JSON args via a small, `std.json`-free byte scanner (`jsonInt`) — sufficient for the flat arg objects and version-stable. - **`feedback_ffi.zig` test** — the in-file invoke test now drives the real `register → start → submit ×2 → get_stats` cycle and asserts the real shapes (so `zig build test` covers it in CI). - **`tests/e2e_full.sh` Step 6** — rewritten to exercise the real tools via the `"arguments"` object (the field BojRest forwards to the FFI); asserts `slot` / `collecting:true` / `recorded:true` / `total_feedback`. Removes the `FEEDBACK_OTRON` skip from #192. - **No Elixir change** — the router already forwards `arguments` and returns the FFI's parsed JSON as the body. The cross-language flow (Zig JSON → Invoker parse → Jason re-encode → test) lands the keys the assertions read. ## Verification — please note `e2e_full.sh` passes `bash -n` + `shellcheck` locally. **The Zig could not be compiled locally**: this sandbox's network is GitHub-only — `ziglang.org` returns **403** and Zig isn't on GitHub releases, and apt is blocked. So the FFI is verified by **CI** (`abi-drift.yml` + `e2e.yml` both run `zig build`) and the added Zig unit test. I'll watch this PR and fix any compile error promptly. (If you'd rather I verify locally, allowing `ziglang.org` in the environment's network policy would let me install Zig 0.15.1.) The ABI is unchanged (only the dispatch body), so `abi-drift` should stay green. 🤖 Draft via Claude Code. --- _Generated by [Claude Code](https://claude.ai/code/session_019tMcRS1Dm1nWjjYP4WvbJa)_ Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What (deliverable-2)
Resolves the E2E REST-contract drift — the 12
e2e_full.shfailures that were red onmain(and inherited by #191). They split into three groups, each fixed at the level that's actually wrong:1.
/menu— server was wrong (real regression) → fixed serverThe Elixir router returned a flat
{count, cartridges}list. Butopenapi.yaml'sMenuResponseand the e2e test and the mcp-bridge's offline-menu fallback all use the tier-grouped shape (tier_teranga/tier_shield/tier_ayo+summary). Restored tier-grouping viaEnum.group_byon each cartridge's declared tier.Verified the grouping against the real manifests with
jq:tier_teranga= 10,tier_ayo= 115 (Shield empty for now), so.tier_teranga | length > 0holds. Consumers already handle the tiered shape (the offline fallback is tiered), so this is safe.2.
/cartridges— test was wrong → fixed testThe server (and the mcp-bridge offline fallback) return an object
{count, cartridges:[…]}. The test didjq lengthexpecting a bare array (so it got2/0). Corrected the test to check the actual shape (.cartridges | length). No server change → the mcp-bridge/cartridgesconsumer is unaffected.3. feedback-o-tron — feature never built → marked truthfully pending
dispatchproxies feedback-mcp to its Zig FFI, andcartridges/feedback-mcp/ffi/feedback_ffi.zig'sboj_cartridge_invokeis a self-described "Grade D Alpha" stub (it only knowsfeedback_register_channel/start_collecting/submit/get_stats, returns{"result":{"status":"stub"}}, andRC_UNKNOWN_TOOLotherwise). The test asserts a fullopen_channel/submit/summary/export/status/list_channelscycle that doesn't exist.Rather than assert an unbuilt feature (or fake-pass it with a stub), the cycle is now guarded behind
FEEDBACK_OTRON(default off → the 7 checks are skipped with a clear reason), matching the repo's "make tests truthful" precedent. FlipFEEDBACK_OTRON=1once the FFI (or a native Elixir handler) implements it.Expected E2E
0 failures — menu (3) + cartridges (2) now pass; feedback (7) skipped.
Verification note
elixir/zig/denoaren't installable in the dev sandbox (apt blocked; the BEAM isn't a single-binary download), so I verified what I could locally — menu grouping viajqagainst the manifests, and the test script viabash -n+shellcheck(clean) — and rely on thee2e.ymlworkflow for the full runtime check.Follow-up
Building feedback-o-tron for real (wire the existing
fb_register/fb_submit/fb_state/fb_get_statsZig state machine intoboj_cartridge_invoke, or a native Elixir handler) is a tracked next step — happy to take it on with whichever approach you prefer.🤖 Draft via Claude Code.
Generated by Claude Code