Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ All notable changes to the OpenArmature specification are documented in this fil

The format is adapted from [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) — subsection labels render as bold paragraphs (rather than H3) to keep the rendered docs-site right-rail TOC focused on releases, and there is no `[Unreleased]` section since the spec tags after every acceptance PR. The spec follows [Semantic Versioning](https://semver.org/).

## [0.16.0] — 2026-05-15

**Added**

- **pipeline-utilities §10.10 — new canonical configuration-time category `checkpoint_state_migration_chain_ambiguous`.** Raised when the registered migration set contains an ambiguity that prevents the engine from picking a unique chain. Two cases trigger the category: a duplicate `(from_version, to_version)` pair at registration (per §10.12.1) and multiple distinct shortest paths between a source / target version pair at chain resolution (per §10.12.2). Non-transient. Mutually exclusive with the other three migration-related categories (`checkpoint_record_invalid`, `checkpoint_state_migration_missing`, `checkpoint_state_migration_failed`) on any given resume; chain-ambiguous routes first because it fires at build or load time before any migration runs or deserialization is attempted. ([proposal 0018](proposals/0018-state-migration-chain-ambiguity.md))
- Conformance fixture `047-state-migration-chain-ambiguous` (pipeline-utilities), covering both the duplicate-pair-at-registration case and the ambiguous-shortest-paths-at-resolution case via the new `expected_chain_ambiguity_error` harness primitive. The primitive accepts the named category surfacing at either build time or during resume, preserving §10.12.2's compile-time-SHOULD / load-time-acceptable carve-out so implementations detecting ambiguity at either point pass the same fixture.

**Changed**

- **pipeline-utilities §10.12.1 — duplicate-pair sentence names the category.** "MUST raise a configuration-time error (the chain is ambiguous)" → "MUST raise `checkpoint_state_migration_chain_ambiguous` (per §10.10) at registration or compile time, before any resume attempt." ([proposal 0018](proposals/0018-state-migration-chain-ambiguity.md))
- **pipeline-utilities §10.12.2 step 2 — multi-shortest-path clause names the category.** "MUST raise a configuration-time error — the same category §10.12.1 raises for duplicate `(from_version, to_version)` pairs" → "MUST raise `checkpoint_state_migration_chain_ambiguous` (per §10.10)." The "Implementations SHOULD detect ambiguity at compile time when feasible" guidance immediately following remains unchanged. ([proposal 0018](proposals/0018-state-migration-chain-ambiguity.md))
- **pipeline-utilities §10.10 — mutual-exclusion paragraph rewritten** to list all four migration-related categories with the new routing precedence (registry well-formedness → version compatibility → chain application → deserialization). ([proposal 0018](proposals/0018-state-migration-chain-ambiguity.md))

**Notes**

- **Pre-1.0 MINOR bump.** Although v0.15.0 already mandated "a configuration-time error" for both ambiguity cases, naming a canonical category that didn't exist before is implementation-visible: implementations that previously raised an arbitrary configuration error (a language-native `ValueError`, a generic `Error`, etc.) must now surface `checkpoint_state_migration_chain_ambiguous` to pass fixture 047. Matches the precedent set by proposal 0014's category additions (`checkpoint_state_migration_missing` / `_failed`), which shipped as the v0.12.0 MINOR bump. The change is small in scope (rename the category surfaced for one specific case) but is correctly classified MINOR per pre-1.0 SemVer.
- Per the "Skip-ahead implementation" governance principle, implementations that have not yet shipped against v0.15.0 may target v0.16.0 directly without implementing v0.15.0 first.

## [0.15.0] — 2026-05-14

**Added**
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ specification text, conformance fixtures, governance rules, and numbered
RFC-style proposals. **No implementation code lives here.** Implementations
are in sibling repositories.

**Current spec version:** [v0.15.0](CHANGELOG.md)
**Current spec version:** [v0.16.0](CHANGELOG.md)

---

Expand Down Expand Up @@ -69,7 +69,7 @@ and architecture are in [`docs/openarmature.md`](docs/openarmature.md).
| Capability | Introduced | Latest | Fixtures | Scope |
|---|---|---|---|---|
| [graph-engine](spec/graph-engine/spec.md) | 0.1.0 | 0.11.0 | 21 | Typed state, async nodes, conditional/static edges, reducers, subgraph composition, observer hooks |
| [pipeline-utilities](spec/pipeline-utilities/spec.md) | 0.5.0 | 0.12.0 | 46 | Middleware (canonical retry + timing), parallel fan-out, checkpointing (with state migration), parallel branches |
| [pipeline-utilities](spec/pipeline-utilities/spec.md) | 0.5.0 | 0.16.0 | 47 | Middleware (canonical retry + timing), parallel fan-out, checkpointing (with state migration), parallel branches |
| [llm-provider](spec/llm-provider/spec.md) | 0.4.0 | 0.14.0 | 28 | Stateless LLM-provider abstraction with canonical error categories, image content blocks for user messages, structured output via `response_schema`, and OpenAI-compatible wire mapping |
| [observability](spec/observability/spec.md) | 0.7.0 | 0.10.0 | 11 | Cross-backend correlation IDs, OpenTelemetry mapping (spans, log correlation, detached trace mode) |
| [prompt-management](spec/prompt-management/spec.md) | 0.15.0 | 0.15.0 | 12 | Named/versioned template fetch + render; composite backends with infrastructure-only fallback; PromptGroup tracing primitive; strict-undefined-by-default variable injection |
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ drift.

---

118 conformance fixtures across five capabilities. Implementations run
119 conformance fixtures across five capabilities. Implementations run
them; if they pass, behavior matches every other conforming runtime.
No "implementation-defined" footguns.

Expand Down
1 change: 1 addition & 0 deletions docs/proposals.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ lifecycle and the proposal template.
| [0015](proposals/0015-llm-provider-multimodal-images.md) | Image content blocks for user messages | llm-provider | Accepted |
| [0016](proposals/0016-llm-provider-structured-output.md) | Structured output | llm-provider | Accepted |
| [0017](proposals/0017-prompt-management-core.md) | Prompt management core | prompt-management | Accepted |
| [0018](proposals/0018-state-migration-chain-ambiguity.md) | State migration chain ambiguity | pipeline-utilities | Accepted |

Click any column header to sort.
1 change: 1 addition & 0 deletions docs/proposals/0018-state-migration-chain-ambiguity.md
4 changes: 2 additions & 2 deletions proposals/0018-state-migration-chain-ambiguity.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# 0018: Pipeline Utilities — State Migration Chain Ambiguity Category and Fixture

- **Status:** Draft
- **Status:** Accepted
- **Author:** Chris Colinsky
- **Created:** 2026-05-15
- **Accepted:**
- **Accepted:** 2026-05-15
- **Targets:** spec/pipeline-utilities/spec.md (modifies §10.10 to add error category; modifies §10.12.1 and §10.12.2 to reference the category by name); spec/pipeline-utilities/conformance/ (adds fixture 047)
- **Related:** 0014 (state-migration hooks)
- **Supersedes:**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# 047 — State Migration Chain Ambiguous

Two cases under one fixture exercising the canonical configuration-time
error category `checkpoint_state_migration_chain_ambiguous` (per §10.10).
Both ambiguity rules in §10.12 raise the same category; this fixture
covers both.

**Spec sections exercised:**

- §10.10 — `checkpoint_state_migration_chain_ambiguous` (configuration-time,
non-transient). Mutually exclusive with the other three migration-related
categories on any given resume.
- §10.12.1 — Two migrations registered with the same `(from_version,
to_version)` pair MUST raise
`checkpoint_state_migration_chain_ambiguous` at registration or
compile time, before any resume attempt.
- §10.12.2 step 2 — When chain resolution finds multiple distinct
shortest paths between a source and target version (same edge
count, different edge sequences), the engine MUST raise
`checkpoint_state_migration_chain_ambiguous`. Implementations
SHOULD detect this at compile time when feasible; load-time
detection is acceptable.

**New harness primitive:** `expected_chain_ambiguity_error: <category>`
accepts the named category surfacing at either build time or during
resume. Preserves §10.12.2's compile-time-SHOULD / load-time-acceptable
carve-out so implementations that detect ambiguity at either point pass
the same fixture without forcing the spec to over-tighten to MUST
compile-time.

**What passes:**

- **`duplicate_pair_at_registration`** — the
`expected_chain_ambiguity_error` assertion fires when two
migrations register the same `(v1, v2)` pair. Duplicate-pair
detection is independent of function identity per §10.12.1, so
both migrations reference the same `should_not_run` mock; the
ambiguity check fires before either function is invoked.
Implementations that detect at registration time satisfy the
assertion via the build-step exception.
- **`ambiguous_shortest_paths_at_resolution`** — the
`expected_chain_ambiguity_error` assertion fires when the
registered migration set forms a diamond (`v1 → v2 → v4` AND
`v1 → v3 → v4`) and the engine must resolve a chain from `v1` to
`v4`. Implementations that detect at compile time satisfy via the
build-step exception; implementations that defer to load time
satisfy via the resume-step exception.

**What fails:**

- The engine silently picks one migration (registration-order, an
arbitrary choice, etc.) when faced with duplicate
`(from, to)` pairs — would mean §10.12.1's MUST-raise rule is
not honored.
- The engine silently picks one shortest path when faced with the
diamond migration graph — would mean §10.12.2's MUST-raise rule
is not honored.
- The engine raises a different category (e.g.,
`checkpoint_state_migration_missing` because the engine treats
the ambiguity as no-path-found) — would mean the routing
invariant in §10.10 is not honored.
- The engine raises the right category but at neither build nor
resume time (e.g., wraps it inside an unrelated exception path)
— would mean the `expected_chain_ambiguity_error` primitive's
either-timing acceptance is not satisfied.
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# State migration — chain ambiguity. Two cases:
# (1) Two migrations with identical (from_version, to_version) registered
# against the same compiled graph (per §10.12.1).
# (2) A diamond migration graph yielding multiple distinct shortest paths
# between a source / target version pair (per §10.12.2).
# Both MUST raise the canonical configuration-time category
# `checkpoint_state_migration_chain_ambiguous` (per §10.10).
#
# The `expected_chain_ambiguity_error` primitive accepts the named
# category surfacing at either build time or during resume — preserves
# §10.12.2's compile-time-SHOULD / load-time-acceptable carve-out so
# implementations that detect ambiguity at either point pass the same
# fixture.

cases:
- name: duplicate_pair_at_registration
description: |
Two migrations register with the same (from_version, to_version)
pair. Per §10.12.1, the engine MUST raise
`checkpoint_state_migration_chain_ambiguous` at registration or
compile time, before any resume attempt.
state:
schema_version: "v2"
fields:
x:
type: int
default: 0
entry: noop
nodes:
noop:
update_pure: {}
edges:
- {from: noop, to: END}
initial_state: {}
checkpointer: sqlite
migrations:
# Two migrations registered against the same (from, to) pair.
# Duplicate-pair detection is independent of function identity
# per §10.12.1 — both reference the same `should_not_run` mock
# because the ambiguity check fires before either function is
# ever invoked. If `should_not_run` is somehow called, an
# implementation has missed the ambiguity check.
- from_version: "v1"
to_version: "v2"
migrate: should_not_run
- from_version: "v1"
to_version: "v2"
migrate: should_not_run
expected_chain_ambiguity_error: checkpoint_state_migration_chain_ambiguous

- name: ambiguous_shortest_paths_at_resolution
description: |
A diamond migration graph: v1 -> v2 -> v4 AND v1 -> v3 -> v4. Both
paths from v1 to v4 have edge count 2; neither is canonically
shortest. Per §10.12.2, the engine MUST raise
`checkpoint_state_migration_chain_ambiguous`. Implementations
SHOULD detect this at compile time by scanning the registered
migration graph; load-time detection (during the resume attempt)
is acceptable per the same section. The
`expected_chain_ambiguity_error` primitive accepts either timing.
state:
schema_version: "v4"
fields:
x:
type: int
default: 0
entry: noop
nodes:
noop:
update_pure: {}
edges:
- {from: noop, to: END}
initial_state: {}
checkpointer: sqlite
seeded_record:
schema_version: "v1"
state: {x: 1}
completed_positions: []
migrations:
# Diamond: v1 -> v2 -> v4 AND v1 -> v3 -> v4. Both shortest paths
# from v1 to v4 have length 2.
- from_version: "v1"
to_version: "v2"
migrate: should_not_run
- from_version: "v2"
to_version: "v4"
migrate: should_not_run
- from_version: "v1"
to_version: "v3"
migrate: should_not_run
- from_version: "v3"
to_version: "v4"
migrate: should_not_run
resume:
from_seeded_record: true
expected_chain_ambiguity_error: checkpoint_state_migration_chain_ambiguous
Loading
Loading