Skip to content

Commit 7eba913

Browse files
Bump spec conformance pin to v0.107.0 (#259)
* Bump spec conformance pin to v0.107.0 Advance the openarmature-spec submodule pin from v0.88.0 to v0.107.0, absorbing proposals 0094-0113 into the v0.17.0 release. This is a mechanical bump: the four sync points (pyproject spec_version, package __spec_version__, conformance.toml spec_pin, the submodule CHANGELOG) plus the test_smoke assertion move together, and AGENTS.md regenerates. No src behavior changes. Moving the pin surfaces the band's conformance fixtures, whose behavior shipped and is unit-tested ahead of the pin but whose harness wiring is not yet in place. All 67 are deferred with categorized reasons, keeping the suite green; the fixture wiring lands in a follow-up PR before the release tag. Manifest notes: 0096, 0097, and 0100 are since 0.16.0 (shipped with the v0.16.0 retrieval work); 0098, 0102, and 0107 are textual-only (conformance-adapter directives with no shipped-module component); 0113 is partial (the general merge-arm malformed handling is not yet built). * Clarify retrieval fixture-deferral comments Two review-driven comment refinements in test_retrieval_provider.py, no behavior change: - Reconcile the header comment above _DEFERRED_FIXTURES: it claimed no retrieval fixtures remain deferred, which the v0.107.0 bump contradicts by re-deferring 042 / 043 / 052. - Refine 042's deferral reason to name the actual gap. The chunk-stitch behavior shipped in v0.16.0 (first-chunk-only response_id nulling, all- or-nothing usage); 042 fails only on the contains_event matcher, which compares a record-valued field (usage) against a dict expectation. From review of PR #259.
1 parent ef5fa23 commit 7eba913

12 files changed

Lines changed: 482 additions & 15 deletions

conformance.toml

Lines changed: 160 additions & 1 deletion
Large diffs are not rendered by default.

openarmature-spec

Submodule openarmature-spec updated 199 files

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Specification = "https://github.com/LunarCommand/openarmature-spec"
6363
openarmature = "openarmature.cli:main"
6464

6565
[tool.openarmature]
66-
spec_version = "0.88.0"
66+
spec_version = "0.107.0"
6767

6868
[dependency-groups]
6969
dev = [

src/openarmature/AGENTS.md

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# OpenArmature — Agent documentation
22

3-
*This is the agent guide bundled with the openarmature Python package, version 0.16.0 (spec v0.88.0). For the full docs site see [openarmature.ai](https://openarmature.ai). For the canonical spec text see [openarmature.org/capabilities](https://openarmature.org/capabilities/). For project-specific conventions for the code you're editing, see the host project's `AGENTS.md` or `CLAUDE.md`.*
3+
*This is the agent guide bundled with the openarmature Python package, version 0.16.0 (spec v0.107.0). For the full docs site see [openarmature.ai](https://openarmature.ai). For the canonical spec text see [openarmature.org/capabilities](https://openarmature.org/capabilities/). For project-specific conventions for the code you're editing, see the host project's `AGENTS.md` or `CLAUDE.md`.*
44

55
## TL;DR
66

@@ -10,7 +10,7 @@ OpenArmature is a workflow framework for LLM pipelines and tool-calling agents:
1010

1111
## Capability contracts
1212

13-
_Sourced from openarmature-spec v0.88.0. Each entry below reproduces §1 (Purpose) and §2 (Concepts) of the capability's `spec.md` verbatim — including additions from accepted proposals that this Python implementation may not yet ship. For per-proposal implementation status (implemented / partial / textual-only / not-yet), see the `conformance.toml` manifest at the repo root. For the full spec text (execution model, error semantics, determinism, observer hooks, etc.) see the linked docs site._
13+
_Sourced from openarmature-spec v0.107.0. Each entry below reproduces §1 (Purpose) and §2 (Concepts) of the capability's `spec.md` verbatim — including additions from accepted proposals that this Python implementation may not yet ship. For per-proposal implementation status (implemented / partial / textual-only / not-yet), see the `conformance.toml` manifest at the repo root. For the full spec text (execution model, error semantics, determinism, observer hooks, etc.) see the linked docs site._
1414

1515
### Capability: `graph-engine`
1616

@@ -168,13 +168,72 @@ the defaults themselves: projection-in is off by default (so `inputs` turns it o
168168
projection-out is on by default via field-name matching (so `outputs` replaces it to avoid ambiguous mixed
169169
rules).
170170

171+
**Declared same-name projection boundary.** As a checked alternative between the implicit
172+
field-name-matching default and the explicit rename maps, a subgraph-as-node MAY declare its boundary as two
173+
field-name *sets* — an **in-set** and an **out-set** — naming the fields that cross by the *same name* on
174+
both sides. The *per-entry* semantics of each set match the explicit maps restricted to same-name pairs: an in-set entry
175+
behaves as an `inputs` entry whose subgraph and parent field names coincide (the parent field's value is
176+
copied into the same-named subgraph field at entry); an out-set entry behaves as an `outputs` entry whose
177+
parent and subgraph field names coincide (the subgraph field's final value is merged into the same-named
178+
parent field via the parent's reducer at exit).
179+
180+
Unlike the maps, the declared form is a **complete boundary declaration with no field-name-matching
181+
fallback** — using it states exactly what crosses:
182+
183+
- The in-set fully determines projection-in: subgraph fields not named receive their schema-declared
184+
defaults; an empty in-set projects nothing in (identical to the no-projection-in default).
185+
- The out-set fully determines projection-out, replacing field-name matching: subgraph fields not named are
186+
discarded; an empty out-set projects nothing out. There is no "absent out-set falls back to field-name
187+
matching" state — a subgraph-as-node that wants field-name matching uses the default (declares no
188+
boundary). An empty set means "nothing," symmetrically for both directions.
189+
190+
Using the declared form governs **both** directions: declaring either set opts the node into the declared
191+
form, and a set that is *omitted entirely* is treated as empty — nothing crosses in that direction, with no
192+
fall-back to field-name matching or to the maps' defaults. Declaring `projects_in` alone, for example,
193+
projects the named fields in and projects **nothing** out (to keep field-name matching on the way out, use
194+
the default form). This is what distinguishes the declared form from the explicit maps, whose `inputs`-only
195+
case *does* leave projection-out at the field-name-matching default (below).
196+
197+
The declared same-name sets and the explicit `inputs`/`outputs` maps are **mutually exclusive** on a single
198+
subgraph-as-node: a node declares its projection with at most one of the default (nothing declared), the
199+
declared same-name sets, or the explicit maps.
200+
171201
Compilation MUST fail with category `mapping_references_undeclared_field` if an `inputs` mapping names a
172202
parent field that is not declared in the parent's state schema, or a subgraph field that is not declared in
173203
the subgraph's state schema. The same rule applies symmetrically to `outputs`. Implementations SHOULD
174204
validate at compile time that the types of mapped parent/subgraph field pairs are compatible (per the
175205
language's type system's notion of compatibility); this is SHOULD rather than MUST because type-system
176206
expressiveness varies across languages.
177207

208+
The same `mapping_references_undeclared_field` rule applies to the declared same-name sets: compilation MUST
209+
fail if an in-set or out-set names a field not declared on the relevant schema (a same-name field is checked
210+
on both the parent and the subgraph schema). Declaring both the same-name sets and an explicit
211+
`inputs`/`outputs` mapping on one subgraph-as-node MUST fail compilation with category
212+
`conflicting_projection_forms`.
213+
214+
**Reducer round-trip warning.** Because projection-out merges through the parent's reducer, a field projected
215+
*in* and then *back out* into the same parent field re-merges: for a reducer that is not
216+
*round-trip-idempotent* — one for which re-applying an already-merged value changes the field — the unchanged
217+
value is merged a second time (e.g. an `append` reducer doubles the list). Of the canonical reducers above,
218+
`last_write_wins`, `merge`, `merge_by_key`, and `dedupe_append` are round-trip-idempotent (a replace, or a
219+
keyed / deduplicated / shallow merge re-applied with the same value, is a no-op); `append`, `concat_flatten`,
220+
`bounded_append`, and `merge_all` are not — `append` / `concat_flatten` / `bounded_append` grow the field on
221+
re-application, and `merge_all` requires a *list-of-mappings* update (see its definition above), so re-merging
222+
a single mapping value is ill-typed and raises `reducer_error` rather than a no-op. A projection
223+
**round-trips** a field when the same parent field is copied into the subgraph and a subgraph field carrying
224+
it is merged back into that same parent field. This occurs when: (a) in the declared same-name form, a field
225+
is named in **both** the in-set and the out-set; (b) in the explicit maps, a parent field is both an `inputs`
226+
value and an `outputs` key mapped to the **same** subgraph field; or (c) with `outputs` absent (projection-out
227+
left at the field-name-matching default), an `inputs` entry copies a parent field into a **same-named**
228+
subgraph field, so field-name matching merges it straight back out. Implementations **MUST** emit a compile-time warning
229+
`projection_reducer_round_trip` (a warning, distinct from the MUST-fail compile-error categories below) when a
230+
projection round-trips a field into a non-round-trip-idempotent **canonical** reducer, and **SHOULD** emit it
231+
when the target is a custom reducer the implementation classifies as non-idempotent. The warning is a
232+
structural heuristic — an implementation cannot statically prove the subgraph left the value unchanged, so it
233+
MAY fire on a round-trip that legitimately replaces the value — and it changes no runtime behavior
234+
(projection-out still merges through the parent's reducer). Authors SHOULD route a round-tripped field through
235+
a replace/idempotent reducer or avoid round-tripping it.
236+
178237
**Compiled graph.** The result of compiling a graph definition. A compiled graph is immutable and executable.
179238
The entry node MUST be declared explicitly by the graph author — there is no implicit "first node added"
180239
default. Compilation MUST fail with a diagnostic error if the graph has: no declared entry node, unreachable
@@ -189,8 +248,10 @@ identifiers (as an error class, error code, or tagged discriminant, per the lang
189248
- `dangling_edge` — an edge references a node name that is not declared.
190249
- `multiple_outgoing_edges` — a node has more than one outgoing edge.
191250
- `conflicting_reducers` — a state field has more than one declared reducer.
192-
- `mapping_references_undeclared_field` — a subgraph-as-node `inputs` or `outputs` mapping names a field
193-
not declared in the relevant state schema.
251+
- `mapping_references_undeclared_field` — a subgraph-as-node `inputs` or `outputs` mapping, or a declared
252+
same-name in-set / out-set, names a field not declared in the relevant state schema.
253+
- `conflicting_projection_forms` — a subgraph-as-node declares both the same-name projection sets and an
254+
explicit `inputs`/`outputs` mapping (the two are mutually exclusive).
194255
- `reducer_configuration_invalid` — a reducer factory was supplied invalid construction parameters
195256
(e.g., `bounded_append(max_len=0)`, `merge_by_key(key=None)`). Raised at field registration / graph
196257
compilation time, before any node body runs. Distinct from `conflicting_reducers`, which is about
@@ -496,8 +557,8 @@ The substrate is intentionally narrow, matching llm-provider's posture:
496557

497558
**Transparency.** Per charter §3.1 principle 8 ("Transparency over abstraction"), the embedding
498559
abstraction surfaces a normalized shape — `EmbeddingResponse`, `EmbeddingUsage` — without hiding
499-
what the underlying provider returned. The `EmbeddingResponse.raw` field carries the parsed provider
500-
response verbatim alongside the normalized fields, and the error categories preserve the underlying
560+
what the underlying provider returned. The `EmbeddingResponse.raw` field carries the provider
561+
response verbatim — an object or an array (§4) — alongside the normalized fields, and the error categories preserve the underlying
501562
provider exception as cause.
502563

503564
#### 2. Concepts
@@ -511,7 +572,7 @@ vectors wrapped in an `EmbeddingResponse`. Bound to a specific embedding model i
511572
instance.
512573

513574
**EmbeddingResponse.** The result of an `embed()` call: the vectors, the model identifier, the
514-
parsed raw response, and — when present — usage information and the provider-returned request
575+
verbatim provider response (`raw`), and — when present — usage information and the provider-returned request
515576
identifier.
516577

517578
**EmbeddingUsage.** A usage record carrying `input_tokens` only — embedding has no output tokens
@@ -534,7 +595,7 @@ the documents sorted by query-relevance with provider-specific scores. Bound to
534595
model identifier per instance.
535596

536597
**RerankResponse.** The result of a `rerank()` call: the sorted scored documents, the model
537-
identifier, the parsed raw response, and — when present — usage information and the
598+
identifier, the verbatim provider response (`raw`), and — when present — usage information and the
538599
provider-returned response identifier.
539600

540601
**RerankUsage.** A usage record with optional `search_units` and optional `input_tokens`, reflecting

src/openarmature/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"""
2626

2727
__version__ = "0.16.0"
28-
__spec_version__ = "0.88.0"
28+
__spec_version__ = "0.107.0"
2929
# Proposal 0052 (spec observability §5.1 / §8.4.1): canonical
3030
# package-registry name for this implementation. Surfaces on every
3131
# OTel invocation span as ``openarmature.implementation.name`` and on

tests/conformance/test_conformance.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,21 @@ def _fixture_id(path: Path) -> str:
8585
"Proposal 0023 canonical state reducers; impl not yet shipped"
8686
),
8787
"038-reducer-error-non-list-update": ("Proposal 0023 canonical state reducers; impl not yet shipped"),
88+
# Proposal 0094 (spec v0.89.0) declared same-name subgraph projection
89+
# boundary + reducer round-trip compile warning. Behavior shipped +
90+
# unit-tested ahead of the pin (test_projection_declared_boundary.py);
91+
# the runtime adapter (declared-boundary subgraph construction) + the
92+
# GraphFixture directive model ride the v0.17.0 fixture-wiring PR.
93+
"040-subgraph-declared-same-name-boundary": (
94+
"Proposal 0094 declared-boundary adapter; rides the v0.17.0 fixture-wiring PR"
95+
),
96+
"041-declared-boundary-compile-errors": (
97+
"Proposal 0094 declared-boundary compile-error adapter; rides the v0.17.0 fixture-wiring PR"
98+
),
99+
"042-reducer-round-trip-warning": (
100+
"Proposal 0094 round-trip warning adapter (expected_compile_warning); "
101+
"rides the v0.17.0 fixture-wiring PR"
102+
),
88103
}
89104

90105

tests/conformance/test_fixture_parsing.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,82 @@ def _id(case: tuple[str, Path]) -> str:
626626
"directive shapes the cross-cap parser does not model, "
627627
"runtime-driven in test_observability"
628628
),
629+
# ----- v0.17.0 spec-pin bump (v0.88.0 -> v0.107.0) ------------------
630+
# These fixtures use directive shapes the cross-capability parser does
631+
# not yet model. Behavior for each proposal shipped + is unit-tested
632+
# ahead of the pin; the fixture-model wiring rides the v0.17.0
633+
# fixture-wiring PR (041 parses cleanly -- only its runtime adapter is
634+
# deferred, in test_conformance).
635+
# Proposal 0094 (v0.89.0) declared-boundary + round-trip warning.
636+
"graph-engine/040-subgraph-declared-same-name-boundary": (
637+
"Proposal 0094 declared-boundary GraphFixture model; rides the v0.17.0 fixture-wiring PR"
638+
),
639+
"graph-engine/042-reducer-round-trip-warning": (
640+
"Proposal 0094 round-trip warning fixture model; rides the v0.17.0 fixture-wiring PR"
641+
),
642+
# Proposal 0095 (v0.91.0) adaptive call-level retry + reask.
643+
"llm-provider/061-call-level-retry-per-attempt-override": (
644+
"Proposal 0095 call.retry / wire_requests directive model; rides the v0.17.0 fixture-wiring PR"
645+
),
646+
"llm-provider/062-call-level-reask-success": (
647+
"Proposal 0095 call.retry / wire_requests directive model; rides the v0.17.0 fixture-wiring PR"
648+
),
649+
"llm-provider/063-call-level-reask-budget-exhausted": (
650+
"Proposal 0095 call.retry / wire_requests directive model; rides the v0.17.0 fixture-wiring PR"
651+
),
652+
"llm-provider/064-call-level-reask-off-by-default": (
653+
"Proposal 0095 call.retry / wire_requests directive model; rides the v0.17.0 fixture-wiring PR"
654+
),
655+
"llm-provider/065-call-level-reask-compose-override": (
656+
"Proposal 0095 call.retry / wire_requests directive model; rides the v0.17.0 fixture-wiring PR"
657+
),
658+
"llm-provider/066-call-level-reask-transient-interleave": (
659+
"Proposal 0095 call.retry / wire_requests directive model; rides the v0.17.0 fixture-wiring PR"
660+
),
661+
# Proposal 0101 (v0.96.0) malformed usage counter.
662+
"llm-provider/070-usage-counter-derived-total-unreported-addend": (
663+
"Proposal 0101 usage-counter fixture model; rides the v0.17.0 fixture-wiring PR"
664+
),
665+
"llm-provider/071-usage-counter-malformed-streaming-terminal-chunk": (
666+
"Proposal 0101 usage-counter fixture model; rides the v0.17.0 fixture-wiring PR"
667+
),
668+
# Proposals 0105 (v0.100.0) / 0108 (v0.103.0) managed-field collision;
669+
# the fixtures carry per-case `invariants` flags the parser does not model.
670+
"llm-provider/072-managed-response-format-collision": (
671+
"Proposal 0105 managed-collision invariants model; rides the v0.17.0 fixture-wiring PR"
672+
),
673+
"llm-provider/073-managed-stream-options-collision": (
674+
"Proposal 0105 managed-collision invariants model; rides the v0.17.0 fixture-wiring PR"
675+
),
676+
"llm-provider/074-managed-structural-model-collision": (
677+
"Proposal 0105 managed-collision invariants model; rides the v0.17.0 fixture-wiring PR"
678+
),
679+
"llm-provider/075-managed-declared-scalar-collision": (
680+
"Proposal 0108 managed-collision invariants model; rides the v0.17.0 fixture-wiring PR"
681+
),
682+
"llm-provider/076-managed-declared-stop-merge": (
683+
"Proposal 0108 managed-collision invariants model; rides the v0.17.0 fixture-wiring PR"
684+
),
685+
"llm-provider/077-managed-declared-stream-collision": (
686+
"Proposal 0108 managed-collision invariants model; rides the v0.17.0 fixture-wiring PR"
687+
),
688+
"llm-provider/078-managed-anthropic-stream-reject": (
689+
"Proposal 0108 managed-collision invariants model; rides the v0.17.0 fixture-wiring PR"
690+
),
691+
"llm-provider/079-managed-anthropic-stop-merge": (
692+
"Proposal 0108 managed-collision invariants model; rides the v0.17.0 fixture-wiring PR"
693+
),
694+
"llm-provider/080-managed-gemini-stop-merge": (
695+
"Proposal 0108 managed-collision invariants model; rides the v0.17.0 fixture-wiring PR"
696+
),
697+
# Proposal 0113 (v0.107.0) malformed extras on a merge-managed field.
698+
"llm-provider/081-managed-declared-stop-malformed": (
699+
"Proposal 0113 malformed merge-managed extras invariants model; rides the v0.17.0 fixture-wiring PR"
700+
),
701+
# Proposal 0109 (v0.104.0) token-budget config extra-key handling.
702+
"prompt-management/037-token-budget-unrecognized-key-ignored": (
703+
"Proposal 0109 token_budget extra-key fixture model; rides the v0.17.0 fixture-wiring PR"
704+
),
629705
}
630706

631707

0 commit comments

Comments
 (0)