fix(feedback): work over the stateless invoker + build boj-invoke in e2e#194
Merged
Conversation
#193's e2e cycle returned {} for two reasons, both fixed here: 1. the e2e "Build FFI libraries" step never built the boj-invoke CLI the Elixir Invoker shells out to (it ran `zig build`, not `zig build invoke`), so every FFI tool invoke classified as :cli_missing -> {}; 2. after `cd ffi/zig`, the cartridge .so loop ran from the wrong directory, so its glob never matched and no cartridge .so was built either. It also surfaced an architectural fact: the invoker is fork-per-request (ADR-0005), so each invoke is a fresh process and the cartridge's in-memory channel state does not persist between HTTP calls — a multi-step register -> submit -> stats cycle cannot span calls. - feedback_ffi.zig: feedback_submit is now self-provisioning. When the target slot is not an active collecting channel (the stateless case) it registers + starts collecting before recording, so a lone submit returns recorded:true in one call. Within one process (pooled invoker / unit test) an already-collecting slot is reused and counts still accumulate. Added a cold-start unit test; all 15 Zig tests pass. - tests/e2e_full.sh Step 6: assert only what a stateless invoker can truthfully deliver — register returns a slot, each submit records, get_stats returns the stats shape. Cross-call accumulation (the full state machine) is left to the pooled-invoker follow-up and is covered by the in-process Zig unit test. - .github/workflows/e2e.yml: build boj-invoke; contain the cd in a subshell so the cartridge .so loop globs from the repo root; tidy the loop to an explicit if. Verified locally with Zig 0.15.2: zig build + zig test (15/15) and driving the real boj-invoke CLI end-to-end. The full Elixir server e2e needs hex.pm (blocked in this sandbox), but boj-invoke is exactly what the Invoker calls, so the feedback invoke path is covered. https://claude.ai/code/session_019tMcRS1Dm1nWjjYP4WvbJa
🏁 path-claims benchCommit NumbersHost-dependent — compare deltas across commits, not absolute values. |
🔍 Hypatia Security ScanFindings: 279 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@ea165f8 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
marked this pull request as ready for review
June 5, 2026 01:25
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.
Why
#193 merged with E2E red — feedback invokes returned
{}. I installed Zig 0.15.2 (it's on PyPI — the sandbox blocksziglang.orgbut not PyPI) and traced it to root cause, locally, end-to-end.The
{}was never my FFI code (it compiles, 15/15 unit tests pass, and the realboj-invokeCLI returns correct JSON). It was two infra faults in one e2e step, plus an architectural fact:boj-invokewas never built — the "Build FFI libraries" step ranzig build, but the CLI the Elixir Invoker shells out to is only produced byzig build invoke. No CLI →:cli_missing→{}for every FFI tool invoke..sos were never built either — aftercd ffi/zig, thefor cart in cartridges/*/ffiloop globbed from the wrong directory, matched nothing, and|| truehid it.register → submit → statscycle cannot span calls (proved: two separate submits bothrecorded:false).What
feedback_ffi.zig—feedback_submitis now self-provisioning: when the slot isn't an active collecting channel (the stateless case) it registers + starts collecting before recording, so a lone submit returnsrecorded:truein one call. Within one process (a pooled invoker, or the unit test) an already-collecting slot is reused and counts still accumulate. Added a cold-start unit test → 15/15 pass.tests/e2e_full.shStep 6 — assert only what a stateless invoker can truthfully deliver: register returns a slot, each submit records,get_statsreturns the stats shape. Cross-call accumulation (the full state machine) is left to the pooled-invoker follow-up and is covered by the in-process Zig unit test..github/workflows/e2e.yml— buildboj-invoke; contain thecdin a subshell so the cartridge loop globs from the repo root; tidy the loop to an explicitif(silences SC2015).Verification (local, Zig 0.15.2 — CI's exact version)
The full Elixir server e2e needs
hex.pm(blocked in this sandbox), butboj-invokeis exactly what the Invoker shells out to, so the feedback invoke path is fully covered. ABI is unchanged (dispatch body only) →abi-driftstays green.🤖 Draft via Claude Code.
Generated by Claude Code