Repository navigation
Wire the observability per-fixture driver keys - #324
Merged
Merged
Conversation
The OTel drivers for fixtures 004, 005, 009 and 011 asserted their claims with hardcoded values instead of reading the fixture, so an edited fixture value went unnoticed. Each now reads its expected keys and is registered in _DRIVER_EXPECTED_KEYS, so a key it does not read fails the run. - 004 matches the declared span_tree and reads no_edge_spans as a closed world over span names. - 005 matches span_tree, span_tree_private and span_tree_global, and reads no_llm_provider_span and no_openarmature_spans_on_global. The node emits the external span itself, as also_emits_via_global_tracer declares, and a leak to the global provider is found by instrumentation scope rather than span name. - 009 runs every case through one driver. It matches span_tree, counts traces against invocation_count and checks each correlation_id invariant by name. A `<uuid>` placeholder now matches any canonical UUIDv4 (conformance-adapter 5.10). - 011 compares the runs and aspects determinism_check names, applies the ignore_attributes patterns and checks its two invariants. The Langfuse runner now reads 037's resume.from_first_run and builds 039 case 3 from the fixture's subgraph_call and fan_out declarations. The expected-key guard runs after the hollow-case check, as in the Langfuse runner, so an invariants-only case is reported as hollow. The harness fidelity test now also fails when a registered driver is still listed as unguarded. The nested-key ledger drops the ten keys these drivers now read.
The shared OTel span-tree matcher only checked that each declared child existed, so a span the expected tree did not list passed unnoticed. A declared list is now the complete set at every level. `children: []` asserts a leaf, a span the tree does not declare fails with its parent named, and a node without `children` leaves them unchecked. The Langfuse runner's observation matcher already treated a non-empty list this way but skipped an empty one, so it now enforces `children: []` as well. 004 now matches its tree from every root its exporter saw, so a span outside the invocation's tree fails too. That covers its hand-written check that the unreachable nodes emit no span, which is removed. The observability suite's harness note says nothing about children, so this reading is pending a spec ruling. Every fixture that runs today passes under it.
There was a problem hiding this comment.
🟡 Changes recommended
UUID validation and root-span matching still allow invalid output to pass conformance checks.
2 open issues
What changed in this PR
Strengthens observability conformance checks by replacing hardcoded assertions with fixture-driven validation.
Changes:
- Wires OTel and Langfuse fixture declarations into their drivers.
- Enforces complete declared span and observation child lists.
- Updates expected-key guards and the unread-key ledger.
| File | Description |
|---|---|
| tests/conformance/test_observability.py | Adds fixture-driven checks and stricter tree matching. |
| tests/conformance/test_observability_langfuse.py | Reads resume and nested-subgraph declarations. |
| tests/conformance/test_harness_fidelity.py | Rejects guarded drivers listed as unguarded. |
| tests/conformance/harness/vocabulary.py | Removes newly consumed keys from the unread ledger. |
Review effort: Balanced
_is_uuidv4 used re.match, and `$` also matches before a final newline, so a UUID with a trailing newline passed the `<uuid>` placeholder and 009's UUID invariants. It now uses fullmatch. 009 matched its span_tree from the invocation root only, so a stray root span carrying the same correlation id passed both the tree and the uniformity invariant in the single-invocation cases. It now matches from every root the exporter saw, as 004 and 005 do.
The OTel runner's UUIDv4 pattern was case-insensitive, so an uppercase id passed the `<uuid>` placeholder and 009's invariants. RFC 9562 writes UUIDs in lowercase, and the checkpoint runner's own check already requires it. The pattern now does too. The span test for pipeline-utilities 031 still called the pattern's match() directly, so a trailing newline passed there. It now goes through _is_uuidv4.
Eight more OTel drivers matched their span_tree from the invocation root only. The tree matcher checks the top level against the roots it is given, so a stray root span went unchecked in 038, 110, 124, 126-129, 131-133, 146, 147, 149, 152 and 153. They now pass every root the exporter saw, as 004, 005 and 009 do, and the matcher's docstring says why.
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.

Wires ten of the twelve observability per-fixture keys left in the unread ledger. The OTel drivers for 004, 005, 009 and 011 asserted their claims with hardcoded values instead of reading the fixture, so an edited fixture value went unnoticed. Each now reads its expected keys and is registered in
_DRIVER_EXPECTED_KEYS, so a key it does not read fails the run.span_treefrom every root its exporter saw, so a span outside the invocation's tree fails too. It readsno_edge_spansas a closed world over span names.span_tree,span_tree_privateandspan_tree_global, and readsno_llm_provider_spanandno_openarmature_spans_on_global. A leak to the global provider is found by instrumentation scope rather than span name.span_tree, counts traces againstinvocation_countand checks eachcorrelation_idinvariant by name. A<uuid>placeholder now matches any canonical UUIDv4 (conformance-adapter section 5.10).determinism_checknames, applies theignore_attributespatterns and checks its two invariants.resume.from_first_runand builds 039 case 3 from the fixture'ssubgraph_callandfan_outdeclarations.The second commit reads a declared
childrenlist as the complete set at every level.children: []asserts a leaf, a span the tree does not declare fails with its parent named, and a node withoutchildrenleaves them unchecked. The Langfuse observation matcher already did this for a non-empty list and now enforceschildren: []too. The observability harness note says nothing aboutchildren, so this reading is pending a spec ruling. Every fixture that runs today passes under it.008's
parent_traceandtracesand 058'stracesstay in the ledger for a follow-up that matches spans per trace.Testing:
openarmature.timing.*attribute between runs stays green, since 011 ignores those attributes.span_treeremoved, so the invariant checks catch it on their own.Review follow-ups:
_is_uuidv4usesfullmatch(), so a trailing newline no longer passes<uuid>or 009's UUID invariants. The UUID pattern is now lowercase-only (RFC 9562), as the checkpoint runner's own check already is, and the 031 span test goes through the same helper. Newline and uppercase mutants on the generated correlation id pass 009 and the 031 span test before these changes and fail after them.