Skip to content

Wire the observability per-fixture driver keys - #324

Merged
chris-colinsky merged 5 commits into
mainfrom
chore/wire-observability-driver-keys
Oct 17, 2026
Merged

chris-colinsky merged 5 commits into
mainfrom
chore/wire-observability-driver-keys

Conversation

@chris-colinsky

@chris-colinsky chris-colinsky commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

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.

  • 004 matches the declared span_tree from every root its exporter saw, so a span outside the invocation's tree fails too. It 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. 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 section 5.10).
  • 011 compares the runs and aspects determinism_check names, applies the ignore_attributes patterns and checks its two invariants.
  • The Langfuse runner 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 also fails when a registered driver is still listed as unguarded.

The second commit reads a declared children list 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 without children leaves them unchecked. The Langfuse observation matcher already did this for a non-empty list and now enforces children: [] too. The observability harness note says nothing about children, so this reading is pending a spec ruling. Every fixture that runs today passes under it.

008's parent_trace and traces and 058's traces stay in the ledger for a follow-up that matches spans per trace.

Testing:

  • Nine source mutants in the observer and engine fail the rewired drivers. A control that varies an openarmature.timing.* attribute between runs stays green, since 011 ignores those attributes.
  • 30 edited-fixture and harness-list probes fail, plus 3 for 039 case 3.
  • For 009, four source mutants fail: a non-UUID id, node spans with a different id, node spans with their own valid UUID, and an id reused across runs. Each also fails with span_tree removed, so the invariant checks catch it on their own.
  • An extra child span under every node span fails 21 fixtures, against 5 before. An extra child under each embedding observation fails Langfuse 083 and 140, against none before.
  • A stray span for 004's unreachable node fails whether it is emitted as a child or as its own root.

Review follow-ups:

  • _is_uuidv4 uses fullmatch(), 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.
  • Every OTel span-tree check now matches from all the roots the exporter saw, not only the invocation root, so a stray root span fails. Under a mutant that emits a stray root carrying the invocation's attributes, 15 more fixtures fail: 038, 110, 124, 126-129, 131-133, 146, 147, 149, 152 and 153.

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.
Copilot AI balanced review requested due to automatic review settings October 17, 2026 14:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Comment thread tests/conformance/test_observability.py Outdated
Comment thread tests/conformance/test_observability.py Outdated
_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.
@chris-colinsky
chris-colinsky merged commit 3acafd3 into main Oct 17, 2026
5 checks passed
@chris-colinsky
chris-colinsky deleted the chore/wire-observability-driver-keys branch October 17, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants