open-standards/jouleclaw/jouleclaw-rs/crates/jouleclaw-otel-genai/README.md
Transaction Science 08faf05ff0 docs: drop vanity test-counts (no-vanity-metrics policy)
Replace drift-prone test/crate counts with shape descriptions in map/ROADMAP.md
and three jouleclaw crate READMEs so the repo passes scripts/check-no-vanity-metrics.sh
(the "describe the shape, not the size" rule). No content meaning lost — "green /
zero warnings" signals retained.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-07 19:00:28 -04:00

43 lines
1.9 KiB
Markdown

# jouleclaw-otel-genai
**Scope**: Typed reference of the OTel GenAI `gen_ai.*` semantic
conventions + JouleClaw `jouleclaw.*` extensions. **Data types
only**.
## Relation to `jouleclaw-otel`
This crate and `jouleclaw-otel` overlap by design:
| Crate | Layer | Surface |
|---|---|---|
| **`jouleclaw-otel-genai`** (this crate) | Typed-attribute reference | `GenAiOperation`, `GenAiSystem`, `GenAiSpanAttrs`, `JouleclawSpanAttrs`, `OperationSpan` |
| **`jouleclaw-otel`** | Projection layer | `receipt_to_span(...)`, `verdict_to_span(...)`, emits `SpanData` with the same attribute names as raw strings |
`jouleclaw-otel` predates this crate and is the *projection
authority* — it knows how to walk every JouleClaw receipt shape
and emit a span. This crate is the *namespace authority* —
upstream callers (e.g. [`jouleclaw-openinference`](../jouleclaw-openinference))
who need typed safety on `gen_ai.*` keys use this crate's enums
to avoid string typos.
Both can coexist because their consumers are different:
- A direct OTel emitter consumes `jouleclaw-otel` and never sees
typed `GenAiOperation`.
- An OpenInference / Arize / Phoenix superset emitter consumes
this crate's types and emits its own attribute pairs.
Neither crate should be deleted; the duplication risk is the
attribute *names* drifting between the two. The convention: when
you add a new `gen_ai.*` key, add it to this crate's enums first,
then mirror it as a string in `jouleclaw-otel`.
## Honest scope
This crate ships:
- `GenAiOperation { Chat | TextCompletion | Embeddings | ToolCall | Code | ImageGen | Speech }`
- `GenAiSystem { OpenAi | Anthropic | Google | Cohere | Mistral | Meta | Jouleclaw | Other(String) }`
- `GenAiSpanAttrs` with builder + `to_otel_attrs() -> Vec<(String, Value)>`
- `JouleclawSpanAttrs` (tier, joules_uj, energy_provenance, receipt.schema, receipt.content_hash, oracle.verdict, cascade.depth, cache.hit)
- `OperationSpan` combining both namespaces
All tests pass.