0089: Embedding / Rerank Typed-Event Output¶
- Status: Accepted
- Author: Chris Colinsky
- Created: 2026-06-28
- Accepted: 2026-06-28
- Targets: graph-engine §6 —
EmbeddingEventgainsoutput_vectors,RerankEventgainsoutput_results, and each event's Privacy and observer-side gating enumeration lists the new payload field. observability §8.4.5 / §8.4.7 — re-sourceembedding.output/retriever.outputfrom the event fields and specify the failure-observation rendering. observability §5.5.13 / §5.5.14 — re-source the OTel rerankopenarmature.rerank.resultsattribute fromRerankEvent.output_results; the §5.5.9 / §5.5.14 typed-event privacy-posture notes list the new fields. New + existing conformance fixtures. - Related: 0049 (typed
LlmCompletionEvent), 0059 (embedding protocol), 0060 (rerank protocol), 0063 (tool-execution observability — the failure-rendering precedent in §8.4.6), 0076 (output_tool_callsonLlmCompletionEvent), 0082 (LlmFailedEventresponse-side surface). - Supersedes:
Summary¶
The typed EmbeddingEvent and RerankEvent (graph-engine §6) carry only the count of their output — dimensions (the inner-vector length) and result_count — not the output payload (the embedding vectors, the scored results). Yet the observability mappings render the actual output: Langfuse §8.4.5 maps embedding.output ← EmbeddingResponse.vectors, Langfuse §8.4.7 maps retriever.output ← the scored results list, the OTel rerank span carries openarmature.rerank.results (§5.5.13), and the conformance fixtures assert all of it. Because an observer's only input is the typed event (per 0049), the output it is told to render is not present on the event — these mappings and their fixtures are unsatisfiable.
This adds an output-payload field to each event, paralleling LlmCompletionEvent.output_content (0049 / 0082): EmbeddingEvent.output_vectors and RerankEvent.output_results, populated on the success event and privacy-gated at the rendering boundary. The Langfuse output mappings (§8.4.5 / §8.4.7) and the OTel rerank attribute (§5.5.13) re-source from these fields. Folding in two adjacent observability gaps in the same area: it specifies the embedding/rerank failure-observation rendering (today unstated, unlike §8.4.6's tool failure), and it confirms the embedding/rerank span is not gated by disable_llm_spans (already stated — §5.5.8 for embedding, §5.5.13 for rerank — a confirmation, no change).
Motivation¶
The success events carry an output count but no output payload, while the mappings render the payload — a contradiction the observer cannot resolve from the event alone:
| typed event (graph-engine §6) | output count carried | renders the output payload at | result |
|---|---|---|---|
EmbeddingEvent |
dimensions (int) |
Langfuse §8.4.5 embedding.output (no OTel output attribute) |
unsatisfiable (Langfuse) |
RerankEvent |
result_count (int) |
Langfuse §8.4.7 retriever.output and OTel §5.5.13 openarmature.rerank.results |
unsatisfiable (both backends) |
LlmCompletionEvent does not have this problem: it carries output_content (+ output_tool_calls), so its observations render the output from the event. Embedding/rerank carry input_strings / query + documents on the input side but have no output-side counterpart. The conformance fixtures for the embedding observation (083) and the rerank observation (108) each assert the populated output under the payload-flag-off case — assertions no conforming observer can satisfy at present, because the field they would read does not exist.
Note the pre-existing embedding/rerank OTel asymmetry: the rerank OTel span renders its output (openarmature.rerank.results, per 0060), while the embedding OTel span renders no output attribute (only the dimensions count + gated input, per 0059) — vectors being larger and noisier than score echoes. This proposal preserves that asymmetry; it only makes the existing rerank attribute satisfiable.
Two adjacent gaps live in the same mapping sections and are cheapest to close in the same pass:
- Failure-observation rendering is unspecified. §8.4.6 (tool) spells out the failure observation (
ERRORlevel onToolCallFailedEvent, witherror_type/error_messagein metadata + the status message). §8.4.5 (embedding) and §8.4.7 (rerank) say nothing about howEmbeddingFailedEvent/RerankFailedEventrender, leaving a cross-implementation gap. disable_llm_spansscope. §5.5.8 (embedding) and §5.5.13 (rerank) already state the span is not gated bydisable_llm_spans(that flag is scoped to LLM completion spans only). This is correct as written; the proposal records the confirmation and makes no change.
Detailed design¶
Anticipated bump: MINOR (pre-1.0). Additive typed-event fields + observability-mapping reconciliations + a failure-rendering specification. No field is removed; observers that could not render output (because the event lacked it) gain the ability.
graph-engine §6 — output fields on the success events¶
EmbeddingEvent.output_vectors—list of list of float. The embedding vectors the call returned (EmbeddingResponse.vectors, retrieval-provider §4). Populated unconditionally on the success event (the provider has the vectors at dispatch); observer-side privacy gating applies at the rendering boundary, the same posture asinput_strings. The inner-vector length continues to surface separately as thedimensionscount.RerankEvent.output_results—list of scored-document records, each{index, relevance_score, document?}(ScoredDocument, retrieval-provider §6). The scored results the call returned (RerankResponse.results). Populated unconditionally on the success event; observer-side privacy gating at the rendering boundary, same posture asquery/documents. Theresult_countcount is retained.- Gating enumerations. The events' Privacy and observer-side gating paragraphs, and the §5.5.9 / §5.5.14 typed-event privacy-posture notes, currently enumerate only the input-side payload fields; they are extended to list
output_vectors/output_resultsas gated payload — matching howLlmCompletionEvent's paragraph enumeratesoutput_content/output_tool_callsalongsideinput_messages. - Failure events unchanged.
EmbeddingFailedEvent/RerankFailedEventcarry no output — no response was received. This is consistent with 0082's framing that the embedding/rerank failure events have no response-side surface (they have no structured-output path, unlikeLlmFailedEvent).
observability §8.4.5 / §8.4.7 — re-source the Langfuse output mapping + specify failure rendering¶
- §8.4.5
embedding.outputis re-sourced fromEmbeddingEvent.output_vectors(the observer's input is the event, not theEmbeddingResponseobject; the event field is itself populated fromEmbeddingResponse.vectorsat dispatch). The privacy posture (disable_provider_payload, default suppressed) is unchanged. For consistency, the section's input row is reworded to source from the event'sinput_stringsrather than "the list passed toembed()" — a wording reconcile, not a behavior change (the value was always event-derivable). - §8.4.7
retriever.outputis re-sourced fromRerankEvent.output_results, identically; its input rows (query/documents) are reworded to source from the event the same way. - Failure-observation rendering (both sections). An
EmbeddingFailedEvent/RerankFailedEventrenders its Langfuse observation atERRORlevel with the §7 error category as the status message anderror_type/error_messagein metadata, via the generic §4.2 / §8.4.2 error mapping — mirroring §8.4.6's tool failure. A confirming fixture pins it cross-implementation.
observability §5.5.13 / §5.5.14 — re-source the OTel rerank output attribute¶
The OTel rerank span's openarmature.rerank.results attribute (§5.5.13) renders the scored results, and §5.5.14 already routes the OTel rerank span through an observer consuming the typed event — so it has the same unsatisfiability as the Langfuse side. It is re-sourced from RerankEvent.output_results. The embedding OTel span is genuinely unchanged: it carries no output attribute (only dimensions + gated input per §5.5.8), so no embedding OTel reconcile is needed.
disable_llm_spans scope — confirmation, no change¶
§5.5.8 (embedding) and §5.5.13 (rerank) already scope disable_llm_spans to LLM completion spans only; neither span is gated by it. The proposal adds no suppression flag and makes no edit here — it records the confirmation so the contract is explicit.
Conformance test impact¶
- The existing embedding (
083) and rerank (108) Langfuse observation fixtures each assert the populatedoutputunder the payload-flag-off case; both are unsatisfiable today and become satisfiable onceoutput_vectors/output_resultsland. Neither is net-new — they already exist and encode the intended behavior. - The OTel rerank fixture asserting
openarmature.rerank.resultsis likewise satisfiable onceoutput_resultslands. - New embedding-failure and rerank-failure observation fixtures pin the
ERROR-level failure rendering (the embedding/rerank analog of the tool-failure observation). - No new directive vocabulary is introduced.
Versioning¶
MINOR bump (pre-1.0): additive typed-event fields, observability-mapping reconciliations (Langfuse §8.4.5 / §8.4.7 + OTel rerank §5.5.13), and a failure-rendering specification. The concrete version is the maintainer's call at acceptance.
Out of scope¶
- An OTel embedding output attribute. Embedding vectors stay off the OTel embedding span (identity + gated input only, per the existing §5.5.8 design). The rerank OTel span keeps its existing
openarmature.rerank.resultsattribute — re-sourced, not added. - Embedding / rerank metrics. The token/usage-metrics surface is the GenAI-metrics domain (0067), unchanged here.
- Any
disable_llm_spanschange. §5.5.8 / §5.5.13 scoping stands; this proposal only records the confirmation.
Alternatives considered¶
- Do nothing. Rejected: the §8.4.5 / §8.4.7 and OTel §5.5.13 output mappings and their fixtures are unsatisfiable as written — exactly the cross-implementation ambiguity the conformance suite exists to remove.
- Add an embedding OTel output attribute (symmetry with rerank). Rejected: embedding vectors are larger and noisier than rerank score echoes; the embedding OTel span's existing design carries identity + gated input only, and the Langfuse Embedding observation is the appropriate home for the vectors. The proposal preserves the pre-existing asymmetry rather than expanding the OTel surface.
- Source the output mapping from the response object directly. Rejected: the observer's only input is the typed event (0049); it has no handle to the
EmbeddingResponse/RerankResponseobject. The event must carry the payload. - Embedding-only; defer rerank. Rejected: the gap is exactly symmetric —
RerankEventhas the same count-not-payload shape against both §8.4.7 and the OTelopenarmature.rerank.resultsattribute — so deferring would leave two rerank mappings unsatisfiable and force a near-duplicate follow-on.
Open questions¶
None. Field names (output_vectors / output_results) follow LlmCompletionEvent.output_content's output_ convention; the failure events carry no output (consistent with 0082); disable_llm_spans needs no change (already settled by §5.5.8 / §5.5.13).