• feat(#17): dispatch-layer op-feed for the provider (slice 2 — Observe)

    vh released this 2026-06-18 00:36:33 -07:00

    Slice 2 of issue #17 — the OBSERVE half. New ratatoskr.provider.opfeed:

    • OpEvent{ts, plane, op, session_id, status, req_summary, resp_summary,
      turn_id=None} — scope-only summaries, never record bodies / PAD content
    • OpSink Protocol + JsonlOpSink (continuous append-only JSONL, INV-007)
    • instrument_provider_app(app, *, plane, sink): an ASGI middleware over the
      built bifrost provider app. Buffers+replays the request, captures the
      response, reads session_id off the dispatch JWT's "sub" claim (INV-005 —
      present for ALL verbs incl. search/get/delete, which bifrost withholds from
      the store method), emits exactly one OpEvent per inbound bifrost-call incl.
      handshake + errors. Read-only over dispatch; store scope semantics untouched
      (INV-004). A sink/summary failure is swallowed + logged, never breaks serve
      (POST-003).
    • Per-verb summaries: search {scope_all,scope_any,top_k}->{hit_count,hits};
      upsert_many {record_count,scopes}->{upserted,replayed}; get/get_many/
      delete_many {ids}->{found_count|deleted}; emit (affect, opaque)->{stored};
      handshake {caps_requested}->{caps_granted,ok}; error->{error: code}
    • serve_memory/serve wired: opt-in via RATATOSKR_OPFEED_PATH (maybe_instrument)

    Resolves the contract's open question: the dispatch JWT DOES carry session_id
    (= the "sub" claim). Tests drive the REAL bifrost dispatch end-to-end with
    minted JWTs. 11 new tests; full suite 453 green; ruff + mypy clean (opfeed.py).

    Downloads