Commit 052b753
fix(feedback): work over the stateless invoker + build boj-invoke in e2e (#194)
## Why
#193 merged with E2E red — feedback invokes returned `{}`. I installed
Zig 0.15.2 (it's on **PyPI** — the sandbox blocks `ziglang.org` but 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 real `boj-invoke` CLI returns correct JSON). It was two infra
faults in one e2e step, plus an architectural fact:
1. **`boj-invoke` was never built** — the "Build FFI libraries" step ran
`zig build`, but the CLI the Elixir Invoker shells out to is only
produced by `zig build invoke`. No CLI → `:cli_missing` → `{}` for
*every* FFI tool invoke.
2. **Cartridge `.so`s were never built either** — after `cd ffi/zig`,
the `for cart in cartridges/*/ffi` loop globbed from the wrong
directory, matched nothing, and `|| true` hid it.
3. **The invoker is fork-per-request** (ADR-0005): each invoke is a
fresh process, so the cartridge's in-memory channel state does **not**
persist between HTTP calls. A multi-step `register → submit → stats`
cycle cannot span calls (proved: two separate submits both
`recorded:false`).
## What
- **`feedback_ffi.zig`** — `feedback_submit` is 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 returns `recorded:true` in 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.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 loop globs from the repo root; tidy the
loop to an explicit `if` (silences SC2015).
## Verification (local, Zig 0.15.2 — CI's exact version)
```
zig build # exit 0, libfeedback_mcp.so
zig test feedback_ffi # All 15 tests passed
# real boj-invoke CLI (what the Invoker calls):
register → {"slot":0,"channel":2,"state":1}
submit → {"recorded":true,"slot":0,"sentiment":1,"feedback_count":1}
stats → {"slot":0,"total_feedback":0,...} # truthfully per-call
```
The full Elixir server e2e needs `hex.pm` (blocked in this sandbox), but
`boj-invoke` is exactly what the Invoker shells out to, so the feedback
invoke path is fully covered. ABI is unchanged (dispatch body only) →
`abi-drift` stays green.
🤖 Draft via Claude Code.
---
_Generated by [Claude
Code](https://claude.ai/code/session_019tMcRS1Dm1nWjjYP4WvbJa)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 3f49db3 commit 052b753
3 files changed
Lines changed: 51 additions & 29 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
83 | | - | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
84 | 88 | | |
85 | | - | |
| 89 | + | |
86 | 90 | | |
87 | 91 | | |
88 | 92 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
309 | 309 | | |
310 | 310 | | |
311 | 311 | | |
312 | | - | |
313 | 312 | | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
314 | 325 | | |
315 | | - | |
316 | | - | |
| 326 | + | |
| 327 | + | |
317 | 328 | | |
318 | 329 | | |
319 | 330 | | |
| |||
409 | 420 | | |
410 | 421 | | |
411 | 422 | | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
412 | 434 | | |
413 | 435 | | |
414 | 436 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
222 | 222 | | |
223 | 223 | | |
224 | 224 | | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
231 | 235 | | |
232 | 236 | | |
233 | 237 | | |
234 | 238 | | |
235 | | - | |
236 | | - | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | 239 | | |
243 | | - | |
| 240 | + | |
244 | 241 | | |
245 | 242 | | |
246 | | - | |
247 | | - | |
| 243 | + | |
| 244 | + | |
248 | 245 | | |
249 | | - | |
| 246 | + | |
250 | 247 | | |
251 | 248 | | |
252 | | - | |
253 | | - | |
| 249 | + | |
| 250 | + | |
254 | 251 | | |
255 | | - | |
| 252 | + | |
| 253 | + | |
256 | 254 | | |
257 | 255 | | |
258 | | - | |
259 | | - | |
260 | | - | |
261 | | - | |
| 256 | + | |
| 257 | + | |
262 | 258 | | |
263 | 259 | | |
264 | 260 | | |
| |||
0 commit comments