Skip to content

Implement proposal 0048 read-symmetric metadata#129

Merged
chris-colinsky merged 4 commits into
mainfrom
feature/0048-read-symmetric-invocation-metadata
Jun 4, 2026
Merged

Implement proposal 0048 read-symmetric metadata#129
chris-colinsky merged 4 commits into
mainfrom
feature/0048-read-symmetric-invocation-metadata

Conversation

@chris-colinsky

@chris-colinsky chris-colinsky commented Jun 4, 2026

Copy link
Copy Markdown
Member

Summary

Proposal 0048 (observability §3.4, spec v0.40.0) adds get_invocation_metadata() as the canonical spec-idiomatic public name for the metadata read API, paralleling the existing set_invocation_metadata() write helper. The python implementation is a one-line module-level rebind of the historical current_invocation_metadata (same function object), exposed through openarmature.observability alongside the original name. Existing callers continue to work unchanged.

The §3.4 read contract was already satisfied end-to-end by the pre-existing ContextVar machinery (returns a MappingProxyType snapshot, silent no-op outside an invocation, no observer emission, per-attempt + per-fan-out scoping inherited from proposals 0034/0040/0045). The value-add in this PR is the canonical name + the §9 Queryable observer pattern documentation.

This PR also bumps the pinned spec from v0.45.0 to v0.46.0, absorbing proposal 0054 (per-invocation observer event drain) into the conformance manifest as not-yet. 0054 is bundled into the v0.12.0 release cycle alongside 0048 per the §9.4 accumulator-lifecycle pairing (without the per-invocation drain, the accumulator pattern would race against the deliver loop on the last-event read); 0054's implementation lands in a follow-on PR.

Notable pieces

  • src/openarmature/observability/metadata.py adds the alias and updates the docstrings on both names to cross-reference each other.
  • src/openarmature/observability/__init__.py re-exports the new name.
  • docs/concepts/observability.md rewrites the Reading the in-scope metadata subsection against the §3.4 contract (per-attempt scoping under retry, three call-site categories, per-async-context fan-out scoping), and adds a new top-level Queryable observer pattern section covering the §9.1 read-method contract, §9.2 async-safety, §9.3 three-channel data-access guidance with a side-by-side table (typed State vs untyped invocation metadata vs queryable accumulator), and §9.4 lifecycle with the explicit drop() discipline. The section also documents the synchronization pattern with drain_events_for (proposal 0054, bundled into v0.12.0) with a callout that the primitive itself ships alongside.
  • conformance.toml flips 0048 to implemented / since = "0.12.0" with a detailed note documenting both the §3.4 contract mechanism and the specific unit tests + predecessor conformance fixtures that pin each part. 0054 is added as not-yet.
  • CHANGELOG.md [Unreleased] Added gets entries for the read API and the §9 docs. The existing spec-pin Changed entry is updated to reflect the v0.46.0 advance and the 0054 bundling.
  • tests/conformance/test_fixture_parsing.py keeps fixtures 043-049 deferred from the cross-capability parser with truthful rationale: they introduce many new directive shapes (augment_metadata, capture_invocation_metadata_into, capture_queryable_observer_read_into, per_attempt_behavior, top-level queryable_observers / inner_subgraphs / caller_metadata / direct_call / sequential_invocations / informative, plus final_state_bounds / direct_call_result / per_invocation in the expected block) that the harness would need to model. The behavioral contract is pinned by unit tests; fixture-shape activation is queued for a future PR. Same precedent as proposal 0045 fixture 039.
  • tests/unit/test_observability_metadata.py adds four new tests for the alias: is-identity with current_invocation_metadata, empty-outside-invocation, MappingProxyType return type (both outside and inside an active invocation), and the end-to-end roundtrip (caller baseline + in-node augment).

Test plan

  • uv run pytest tests/ — 1098 passed, 307 skipped
  • uv run pytest tests/unit/test_observability_metadata.py — 48 passed
  • uv run python scripts/check_conformance_manifest.py — 51/51 entries consistent
  • uv run ruff check . + uv run ruff format --check . — clean
  • uv run pyright src/ tests/ — 0 errors
  • uv run mkdocs build --strict — clean
  • Spot-check the rendered §9 Queryable observer pattern section in the browser (the three-channel table is the load-bearing piece)

Adds get_invocation_metadata() as the spec-idiomatic public name
for the observability §3.4 read API, paralleling the existing
set_invocation_metadata() write helper. The alias is a direct
module-level rebind of the historical current_invocation_metadata
(same function object), exported through openarmature.observability
alongside the original name. Existing callers continue to work
unchanged.

Bumps the pinned spec from v0.45.0 to v0.46.0 and absorbs proposal
0054 (per-invocation observer event drain) into the conformance
manifest as not-yet; 0054 is bundled into the v0.12.0 release per
the §9.4 accumulator-lifecycle pairing and lands in a follow-on PR.

Adds a §9 *Queryable observer pattern* section to the observability
concepts page documenting the convention-only observer-attached
read-method pattern, the read-method contract, async-safety, the
three-channel data-access guidance (State / invocation metadata /
queryable observer accumulator), and the accumulator lifecycle
with the §9.4 drop() discipline.

Conformance fixtures 043-049 stay deferred from the cross-capability
parser (they introduce many new directive shapes the harness would
need to model); the §3.4 read contract is pinned by explicit unit
tests plus the predecessor proposal 0034/0040/0045 conformance
fixtures that exercise the same underlying ContextVar machinery.
Copilot AI review requested due to automatic review settings June 4, 2026 01:27

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.

Pull request overview

Adds the spec-canonical get_invocation_metadata() name (proposal 0048) as an alias to the existing invocation-metadata read API, updates exports/tests/docs accordingly, and bumps the pinned spec version to v0.46.0 (adding proposal 0054 as not-yet in the manifest).

Changes:

  • Introduce and re-export get_invocation_metadata as an alias of current_invocation_metadata, plus unit tests for alias identity and roundtrip behavior.
  • Update observability docs with the §3.4 read API guidance and add a new “Queryable observer pattern” section (§9).
  • Bump spec pin/version references to v0.46.0 across runtime constants, pyproject, conformance manifest, and smoke tests.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/unit/test_observability_metadata.py Adds unit tests pinning the new alias name and end-to-end metadata read/write behavior.
tests/test_smoke.py Updates expected __spec_version__ to v0.46.0.
tests/conformance/test_fixture_parsing.py Updates fixture deferral rationale for 0048 and adds new deferrals for 0054 fixtures.
src/openarmature/observability/metadata.py Defines get_invocation_metadata alias, updates docstrings, and exports it via __all__.
src/openarmature/observability/init.py Re-exports get_invocation_metadata from the public observability surface.
src/openarmature/AGENTS.md Updates embedded spec version text to v0.46.0.
src/openarmature/init.py Bumps __spec_version__ to v0.46.0.
pyproject.toml Bumps [tool.openarmature].spec_version to v0.46.0.
docs/concepts/observability.md Rewrites “Reading the in-scope metadata” section and adds the §9 queryable observer pattern documentation.
conformance.toml Bumps spec_pin to v0.46.0; marks 0048 implemented; adds 0054 as not-yet.
CHANGELOG.md Updates Unreleased notes for spec-pin bump and documents the 0048 alias + §9 docs additions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/concepts/observability.md Outdated
Comment thread conformance.toml Outdated
Both in-page callouts in docs/concepts/observability.md (the new
proposal-0054 bundling note and the pre-existing Langfuse SDK
version compatibility note) were using `!!! note`, which renders in
Material's default blue. The 13 example walk-through pages use
`!!! info "Source"`, which the project CSS paints in the brand
lavender. Flip the two concept-page callouts to `!!! info` so every
admonition site-wide picks up the same brand styling.

Also refresh the now-stale CSS comment that claimed the only
`!!! info` usage was the Source box.
The v0.12.0 python retry middleware manages the attempt_index
ContextVar but does not reset the invocation-metadata ContextVar
between attempts; a write from a failed retry attempt remains
visible on the next attempt. The original PR docs and conformance
note claimed per-attempt scoping was satisfied, which is wrong.

Walks the docs back: the per-attempt sentence is dropped and an
explicit info callout names the gap and points at the follow-on
PR that will land the engine-side reset + the pinning unit test.

Flips conformance.toml status for proposal 0048 from implemented
to partial. The note field documents what ships in v0.12.0 (read
API + queryable observer pattern docs + per-async-context scoping
under fan-out / parallel-branches) versus the open retry-side gap.
Copilot AI review requested due to automatic review settings June 4, 2026 02:04

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.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Comment thread docs/concepts/observability.md
Comment thread tests/conformance/test_fixture_parsing.py Outdated
The persist() example in the queryable observer pattern docs was
reading state.invocation_id, but a default State has no such field.
Switch the snippet to bind invocation_id from
current_invocation_id() (the supported in-node accessor) with a
brief note that it is guaranteed non-None inside a node body.

The 0048 fixture-deferral comment in test_fixture_parsing.py
claimed unit tests covered per-attempt scoping under retry and
per-async-context scoping under fan-out. Neither is true: there
are no retry-attempt tests in test_observability_metadata.py, and
the fan-out coverage lives in the runtime conformance harness via
the predecessor proposal 0034/0040 fixtures, not as unit tests
here. Rewrite the comment to be honest about what each pin
actually covers and to flag the retry-side gap.
@chris-colinsky chris-colinsky merged commit 39cb4f3 into main Jun 4, 2026
6 checks passed
@chris-colinsky chris-colinsky deleted the feature/0048-read-symmetric-invocation-metadata branch June 4, 2026 02:39
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