Skip to content

Commit 256ab2a

Browse files
Move docstring spec-refs into # comments (#206)
Relocate spec citations (section references, proposal numbers, and "the spec" attributions) out of Python docstrings into # comments across src/ and tests/, so docstrings describe behavior and the adjacent comments carry the spec provenance. Extends the per-PR docstring fixes from 0059b and 0060a into a full codebase sweep. Scope: only spec citations move. Bare capitalized RFC-2119 contract words (MUST / MAY) stay in docstrings as behavioral contract language, matching the establishing cleanup in #169. The added # comments reproduce the citations; nothing is deleted, only relocated. No behavior change.
1 parent 01f93d3 commit 256ab2a

10 files changed

Lines changed: 59 additions & 33 deletions

File tree

src/openarmature/graph/events.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ class LlmRetryAttemptEvent:
709709
``finish_reason`` / ``output_content`` / ``output_tool_calls``):
710710
populated on a successful attempt; ``None`` / empty list on a
711711
failed attempt. ``output_tool_calls`` is the source the OTel
712-
observer renders the §5.5.1 / §5.5.10 output tool-call attributes
712+
observer renders the output tool-call attributes
713713
from (this is the per-attempt event that drives the LLM span).
714714
- failure side (``error_category`` / ``error_message`` /
715715
``error_type``): populated on a failed attempt; ``None`` on a
@@ -745,8 +745,9 @@ class LlmRetryAttemptEvent:
745745
# Proposal 0076: the attempt's output tool calls (ToolCall records),
746746
# mirroring LlmCompletionEvent.output_tool_calls. Populated on a
747747
# successful attempt; empty list on a failed one (no response). The
748-
# OTel observer renders the output tool-call span attributes from
749-
# this field (the per-attempt event is the LLM-span source).
748+
# OTel observer renders the observability §5.5.1 / §5.5.10 output
749+
# tool-call span attributes from this field (the per-attempt event is
750+
# the LLM-span source).
750751
output_tool_calls: list["ToolCall"] = field(default_factory=list["ToolCall"])
751752

752753

src/openarmature/graph/parallel_branches.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,12 @@ async def run(self, state: ParentT) -> Mapping[str, Any]:
139139
"compiled.invoke)."
140140
)
141141

142+
# Spec pipeline-utilities §11.10: a branch dispatches when its ``when``
143+
# predicate is absent or returns true.
142144
def dispatched_branches(self, state: Any) -> list[tuple[str, BranchSpec[Any]]]:
143145
"""Return the branches that dispatch for ``state``, in insertion
144146
order: every declared branch whose ``when`` predicate is absent or
145-
returns true (§11.10).
147+
returns true.
146148
147149
``when`` MUST be a pure function of the dispatch-time parent state,
148150
so this is deterministic and safe to evaluate both here (the
@@ -288,6 +290,11 @@ async def innermost(s: Any) -> Mapping[str, Any]:
288290
return await self._fail_fast(state, tasks, contributions)
289291
return await self._collect(state, tasks, contributions, errors)
290292

293+
# Spec pipeline-utilities §11.4 (the buffer-then-project subgraph path is
294+
# bypassed for inline callables) + §11.7 (per-leg branch middleware). The
295+
# callable emits its own graph-engine §6 started/completed pair keyed by
296+
# ``branch_name``, rendered per observability §5.7 as a per-branch dispatch
297+
# span with no inner-node span beneath it.
291298
async def _dispatch_callable_branch(
292299
self,
293300
branch_name: str,
@@ -300,14 +307,14 @@ async def _dispatch_callable_branch(
300307
301308
The callable reads the parent state and returns a parent-shaped
302309
partial update directly — no subgraph, no ``inputs`` / ``outputs``
303-
projection (§11.4). Branch ``middleware`` (e.g. a per-leg
304-
``FailureIsolationMiddleware``, §11.7) wraps the callable.
310+
projection. Branch ``middleware`` (e.g. a per-leg
311+
``FailureIsolationMiddleware``) wraps the callable.
305312
306313
A callable branch has no inner nodes, so it IS the unit of work:
307314
it emits one ``started`` / ``completed`` observer pair keyed by its
308-
``branch_name`` (graph-engine §6), which the observers render as the
309-
branch's per-branch dispatch span with NO inner-node span beneath it
310-
(observability §5.7). To render that way the pair is emitted at the
315+
``branch_name``, which the observers render as the
316+
branch's per-branch dispatch span with NO inner-node span beneath it.
317+
To render that way the pair is emitted at the
311318
parallel-branches NODE's own namespace (not a descended branch
312319
namespace), tagged with ``branch_name`` (set on the ContextVar in
313320
``run_branch``): an event at a pb-node's own namespace carrying a

src/openarmature/observability/langfuse/client.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,13 @@ def trace(
185185
Implementations track Traces internally; observation calls
186186
pass `trace_id` to associate.
187187
188-
`session_id` / `user_id` (proposal 0064 §8.4.1) populate
188+
`session_id` / `user_id` populate
189189
Langfuse's cross-trace grouping fields (the Sessions / Users
190190
dashboards); each is unset when its source is absent.
191191
"""
192192
# Spec §8.4.1: the Trace id is the OA invocation_id verbatim.
193+
# session_id / user_id (proposal 0064) populate Langfuse's
194+
# cross-trace grouping (the Sessions / Users dashboards).
193195
...
194196

195197
# The current observer doesn't invoke this method — it sets the
@@ -248,6 +250,8 @@ def generation(
248250
start_time: datetime | None = None,
249251
) -> LangfuseGenerationHandle: ...
250252

253+
# Spec proposal 0063: dedicated Tool observation (Langfuse asType="tool"),
254+
# not a Generation with a discriminator.
251255
def tool(
252256
self,
253257
*,
@@ -261,7 +265,7 @@ def tool(
261265
output: Any = None,
262266
start_time: datetime | None = None,
263267
) -> LangfuseSpanHandle:
264-
"""Open a dedicated Tool observation (proposal 0063, Langfuse
268+
"""Open a dedicated Tool observation (Langfuse
265269
``asType="tool"``). Like :meth:`generation` minus the model /
266270
usage / prompt surface: a Tool carries ``input`` (arguments) /
267271
``output`` (result) / metadata / level. Returns a minimal

src/openarmature/observability/langfuse/observer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1821,9 +1821,10 @@ def _handle_typed_llm_failed(self, event: LlmFailedEvent) -> None:
18211821
status_message=event.error_category,
18221822
)
18231823

1824+
# Spec proposal 0063: dedicated Langfuse Tool observation (asType="tool").
18241825
def _handle_tool_call(self, event: ToolCallEvent | ToolCallFailedEvent) -> None:
18251826
"""Open + close a dedicated Tool observation (Langfuse
1826-
``asType="tool"``, proposal 0063) under the calling node's Span
1827+
``asType="tool"``) under the calling node's Span
18271828
observation. DEFAULT level on a ToolCallEvent; ERROR (with
18281829
``error_type`` / ``error_message`` in metadata and as the status
18291830
message) on a ToolCallFailedEvent. ``input`` (arguments) /

src/openarmature/observability/llm_event.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ class LlmEventPayload(BaseModel):
147147
caller_invocation_metadata: dict[str, Any] = Field(default_factory=dict)
148148

149149

150+
# Spec observability §5.5.5: tool-call serialization.
150151
def serialize_tool_calls(tool_calls: Sequence[ToolCall]) -> list[dict[str, Any]]:
151-
"""The observability §5.5.5 tool-call serialization,
152-
``[{id, name, arguments}, ...]``.
152+
"""Serialize tool calls to ``[{id, name, arguments}, ...]``.
153153
154154
The single home for the encoding, shared by the input-message
155155
payload (the provider's ``input.messages`` serialization, where the

src/openarmature/observability/otel/observer.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ def _serialize_for_attribute(value: Any) -> str:
359359
renders via its ``str()`` rather than raising inside the observer
360360
(which would lose the whole span). It is a no-op for the
361361
already-encodable payloads (messages, params); it matters for the
362-
proposal 0063 tool ``result``, which is an opaque, language-idiomatic
362+
tool ``result``, which is an opaque, language-idiomatic
363363
value the tool produced (a model, dataclass, datetime, ...)."""
364364
return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False, default=str)
365365

@@ -1389,17 +1389,19 @@ def _emit_checkpoint_save_span(self, event: NodeEvent) -> None:
13891389
# active_prompt_group snapshots taken at dispatch time — NOT the
13901390
# ContextVar. The dispatch worker's task-local Context doesn't see
13911391
# node-body ContextVar writes.
1392+
# Spec observability §11 GenAI metrics. §11.2: the attempt index is
1393+
# deliberately not a metric dimension (cardinality control).
13921394
def _record_llm_metrics(self, event: LlmRetryAttemptEvent) -> None:
1393-
"""Record the §11 GenAI metric observations for one LLM-call
1395+
"""Record the GenAI metric observations for one LLM-call
13941396
attempt.
13951397
13961398
Duration is recorded for every attempt (including a failed one,
13971399
carrying ``error.type``); token usage only when the attempt
13981400
returned a usage record (a failed attempt has none). Sourced from
13991401
the per-attempt ``LlmRetryAttemptEvent`` — one duration sample per
14001402
attempt under call-level retry, matching the per-attempt span
1401-
model. The attempt index is deliberately not a dimension (§11.2
1402-
cardinality).
1403+
model. The attempt index is deliberately not a dimension
1404+
(cardinality control).
14031405
"""
14041406
if self._duration_histogram is None or self._token_histogram is None:
14051407
return
@@ -1615,16 +1617,18 @@ def _handle_typed_llm_retry_attempt(self, event: LlmRetryAttemptEvent) -> None:
16151617
self._run_enrichers(span, event)
16161618
span.end(end_time=end_time_ns)
16171619

1620+
# Spec proposal 0063 tool span. Payload attributes (arguments / result)
1621+
# follow observability §5.5.4 opt-out + §5.5.5 truncation.
16181622
def _handle_tool_call(self, event: ToolCallEvent | ToolCallFailedEvent) -> None:
1619-
"""Emit an ``openarmature.tool.call`` span for a tool execution
1620-
(proposal 0063), parented under the calling node.
1623+
"""Emit an ``openarmature.tool.call`` span for a tool execution,
1624+
parented under the calling node.
16211625
16221626
A ``ToolCallEvent`` renders OK with the result attribute; a
16231627
``ToolCallFailedEvent`` renders ERROR with the standard OTel
16241628
``error.type`` attribute + an exception event carrying the
16251629
message. ``arguments`` / ``result`` are payload, gated by
1626-
``disable_provider_payload`` (§5.5.4) + the §5.5.5 truncation
1627-
contract. The OA-namespace ``openarmature.tool.*`` attributes
1630+
``disable_provider_payload`` and truncated. The OA-namespace
1631+
``openarmature.tool.*`` attributes
16281632
mirror the Development ``gen_ai.tool.*`` surface, which is NOT
16291633
emitted in v1. ``disable_llm_spans`` does not gate this span.
16301634
"""

tests/conformance/adapter.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,11 +1063,12 @@ def _add_fan_out_node(
10631063
)
10641064

10651065

1066+
# Spec proposal 0075: callable branch ``call:`` directive.
10661067
def _build_call_fn(
10671068
branch_name: str,
10681069
call_cfg: Mapping[str, Any],
10691070
) -> Callable[[Any], Awaitable[Mapping[str, Any]]]:
1070-
"""Translate a callable branch's ``call:`` directive (proposal 0075)
1071+
"""Translate a callable branch's ``call:`` directive
10711072
into an async function over the parent state.
10721073
10731074
Reuses the node-behavior factories (``update`` / ``flaky`` /
@@ -1087,8 +1088,9 @@ def _build_call_fn(
10871088
raise ValueError(f"callable branch {branch_name!r}: unsupported call directive {dict(call_cfg)!r}")
10881089

10891090

1091+
# Spec proposal 0075 §11.10: branch ``when:`` predicate.
10901092
def _build_when_predicate(when_cfg: Mapping[str, Any]) -> Callable[[Any], bool]:
1091-
"""Translate a branch ``when:`` directive (proposal 0075 §11.10) into
1093+
"""Translate a branch ``when:`` directive into
10921094
a parent-state predicate. Supports ``{field: <name>}`` — a truthy
10931095
check on a parent-state field at dispatch time."""
10941096
if "field" in when_cfg:
@@ -1115,7 +1117,7 @@ def _add_parallel_branches_node(
11151117
11161118
A branch is either a ``subgraph`` (name resolved against the shared
11171119
``subgraphs`` registry, with optional ``inputs`` / ``outputs``) or an
1118-
inline ``call`` (proposal 0075), and may carry a ``when`` predicate.
1120+
inline ``call``, and may carry a ``when`` predicate.
11191121
``branch_middleware`` maps branch-name to a pre-translated middleware
11201122
list; the test driver populates it from each branch's ``middleware:``
11211123
block.

tests/conformance/harness/directives.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,13 +305,14 @@ def _normalize_instance_middleware(cls, data: Any) -> Any:
305305
return data_dict
306306

307307

308+
# Spec proposal 0075: parallel-branches branch entry.
308309
class ParallelBranchSpec(_AllowExtras):
309310
"""One entry inside a ``parallel_branches.branches`` mapping.
310311
311312
A branch's work is given by exactly one of ``subgraph`` (a compiled
312313
subgraph referenced by name, with optional ``inputs`` / ``outputs``)
313314
or ``call`` (an inline node-behavior directive — ``update`` / ``flaky``
314-
/ ``raises`` — run as a function over the parent state, proposal 0075).
315+
/ ``raises`` — run as a function over the parent state).
315316
An optional ``when`` directive (``{field: <name>}``) skips the branch
316317
at dispatch. Permissive on extras because fixtures may carry extra
317318
knobs (e.g., per-branch annotations the harness ignores).
@@ -385,8 +386,9 @@ class MockToolSpec(_AllowExtras):
385386
raises: dict[str, Any] | None = None
386387

387388

389+
# Spec proposal 0063: tool-using node directive.
388390
class CallsToolSpec(_AllowExtras):
389-
"""Tool-using node (proposal 0063): the node body enters the
391+
"""Tool-using node: the node body enters the
390392
``with_tool_call`` instrumentation scope, runs the ``mock_tool``, and
391393
OA emits the ToolCallEvent / ToolCallFailedEvent. ``tool_call_id`` is
392394
optional (null = a standalone instrumented function);
@@ -400,11 +402,12 @@ class CallsToolSpec(_AllowExtras):
400402
stores_result_in: str | None = None
401403

402404

405+
# Spec proposal 0059: embedding-using node directive.
403406
class CallsEmbedSpec(_AllowExtras):
404407
"""Embedding-using node: sends ``input`` to a mock embedding provider
405408
and stores the result in ``stores_response_in``. Used by the
406409
GenAI-metrics embedding fixture (089). The embedding capability
407-
(proposal 0059) is unimplemented in python until v0.16.0, so 089 is
410+
is unimplemented in python until v0.16.0, so 089 is
408411
deferred at the runner; this directive is modelled here only so the
409412
fixture parses + round-trips through the harness schema."""
410413

tests/integration/test_langfuse_sdk_adapter.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,16 +249,19 @@ async def test_sdk_adapter_generation_timestamps_round_trip_through_langfuse() -
249249
client.shutdown()
250250

251251

252+
# Spec proposal 0064 §8.4.1: trace(session_id=, user_id=) populates the live
253+
# Trace's sessionId / userId grouping. proposal 0020 (sessions capability) will
254+
# later supply openarmature.session_id along the same passthrough.
252255
@pytest.mark.integration
253256
async def test_sdk_adapter_populates_session_and_user_id_on_live_langfuse() -> None:
254-
"""End-to-end (proposal 0064 §8.4.1): trace(session_id=, user_id=)
257+
"""End-to-end: trace(session_id=, user_id=)
255258
populates the live Trace's sessionId / userId grouping fields.
256259
257260
The observer leaves session_id dormant until the sessions capability
258-
(proposal 0020) supplies openarmature.session_id, but the adapter
261+
supplies openarmature.session_id, but the adapter
259262
passes whatever it is given, so this exercises BOTH passthroughs at
260-
the SDK boundary: when 0020 lands, the session_id rides the same
261-
propagate_attributes path the userId promotion uses today.
263+
the SDK boundary: when the sessions capability lands, the session_id
264+
rides the same propagate_attributes path the userId promotion uses today.
262265
"""
263266
from langfuse import Langfuse
264267

tests/unit/test_tool_call.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
"""Unit tests for the tool-call instrumentation scope (proposal 0063).
1+
# Spec proposal 0063: tool-call instrumentation scope.
2+
"""Unit tests for the tool-call instrumentation scope.
23
34
Exercise ``with_tool_call`` directly by installing a collecting dispatch
45
callback + a node-scope identity into the correlation ContextVars, the

0 commit comments

Comments
 (0)