Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
383ace3
Add execplan for orchestration architecture enforcement (2.4.5)
leynos Jun 15, 2026
89385e7
Record orchestration enforcement plan start
leynos Jun 26, 2026
4b9dc24
Add orchestration architecture fixture harness
leynos Jun 26, 2026
7e9ad80
Record M0 review completion
leynos Jun 26, 2026
5732f8c
Split orchestration graph modules
leynos Jun 26, 2026
15ea317
Record M1 review completion
leynos Jun 26, 2026
9dc853e
Extract worker workload contract
leynos Jun 26, 2026
e84c684
Record M2 review completion
leynos Jun 26, 2026
e017f37
Enforce checkpoint payload boundaries
leynos Jun 26, 2026
5ada412
Record M3 review completion
leynos Jun 26, 2026
c823750
Document orchestration enforcement
leynos Jun 26, 2026
63ab755
Record M4 review completion
leynos Jun 26, 2026
e34aed5
Restore orchestration Hecate groups
Jul 21, 2026
3e1c4a9
Fix orchestration documentation spelling
Jul 21, 2026
3bc41d6
Refactor checkpoint origin validation
leynos Jul 28, 2026
8a1b942
Extract Hecate config assertions
leynos Jul 28, 2026
0c0bff5
Mark architecture enforcement plan complete
leynos Aug 2, 2026
7b9106a
Document workload class examples
leynos Aug 2, 2026
4e430d7
Align orchestration architecture documentation
leynos Aug 2, 2026
30e3317
Complete orchestration architecture ExecPlan
leynos Aug 2, 2026
c3c01ac
Enforce orchestration node boundary
leynos Aug 2, 2026
957f683
Harden structured payload serialization
leynos Aug 2, 2026
c00716c
Tighten orchestration helper contracts
leynos Aug 2, 2026
5b1e8aa
Adapt orchestration changes to current checks
leynos Aug 25, 2026
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
15 changes: 9 additions & 6 deletions docs/adr/adr-014-hexagonal-architecture-enforcement.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ SDK integrations live in adapters. Ruff enforces general import hygiene, but it
does not know the repository's dependency graph. A module can therefore import
in the wrong direction while still satisfying ordinary lint rules.

The immediate need is roadmap item `1.5.4`: enforce the current service
scaffold boundaries. The deeper orchestration-specific checks for LangGraph
nodes, Celery task payloads, and checkpoint state remain roadmap item `2.4.5`.
The immediate need was roadmap item `1.5.4`: enforce the current service
scaffold boundaries. ADR-016 records the later orchestration-specific checks
for LangGraph nodes, Celery task payloads, and checkpoint state.

## Decision

Expand Down Expand Up @@ -73,8 +73,8 @@ published structural surface.
- Constraint-name constants used by service-layer conflict handling now live in
`episodic.canonical.constraints`. SQLAlchemy models import those constants
rather than owning the only copy.
- `2.4.5` remains responsible for LangGraph-node-specific policies, Celery
checkpoint payload audits, and deeper orchestration checks.
- ADR-016 extends this base policy with LangGraph-node-specific policies,
Celery task checks, and checkpoint payload audits.
- Hecate replaces the former repo-local `episodic.architecture` checker. New
architecture groups are added in `pyproject.toml`; generic checker semantics
belong upstream in Hecate.
Expand All @@ -87,7 +87,8 @@ Hecate adoption ExecPlan: `docs/execplans/adopt-hecate.md`.[^3] Hecate
configuration: `[tool.hecate]` in `pyproject.toml`.[^4] Tests:
`tests/test_architecture_enforcement.py`, `tests/test_port_contracts.py`,
`tests/features/architecture_enforcement.feature`, and
`tests/steps/test_architecture_enforcement_steps.py`.[^5]
`tests/steps/test_architecture_enforcement_steps.py`.[^5] Orchestration
enforcement extension: ADR-016.[^6]

[^1]: Roadmap items `1.5.4` and `2.4.5` in `docs/roadmap.md`
[^2]: ExecPlan:
Expand All @@ -98,3 +99,5 @@ configuration: `[tool.hecate]` in `pyproject.toml`.[^4] Tests:
`tests/test_port_contracts.py`,
`tests/features/architecture_enforcement.feature`, and
`tests/steps/test_architecture_enforcement_steps.py`
[^6]: Orchestration architecture enforcement:
`docs/adr/adr-016-orchestration-architecture-enforcement.md`
97 changes: 97 additions & 0 deletions docs/adr/adr-016-orchestration-architecture-enforcement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# ADR-016: Orchestration architecture enforcement

## Status

Accepted, 2026-06-26. LangGraph node modules, Celery task modules, and
orchestration checkpoint payload modules are enforced as dedicated Hecate
groups.

## Date

2026-06-26.

## Context and problem statement

ADR-014 introduced Hecate as the import-boundary checker for the core hexagonal
architecture. That policy covered domain, application, adapter, and
composition-root modules, but roadmap item `2.4.5` still needed deeper
orchestration-specific checks.

The risk was concentrated in three places:

- LangGraph nodes could become convenient places to import storage, HTTP, or
vendor Software Development Kit (SDK) adapters directly.
- Celery task modules could bypass worker composition roots and instantiate
concrete infrastructure.
- Durable checkpoint payload DTOs could accrete canonical Object-Relational
Mapping (ORM) entities, provider SDK responses, or other non-JSON state.

## Decision drivers

- Preserve ports as the integration boundary for orchestration code.
- Keep LangGraph framework mechanics out of node functions.
- Keep Celery task modules independent of concrete worker runtime wiring.
- Keep checkpoint payloads provider-neutral and JSON-shaped.
- Make the policy visible in deterministic tests rather than relying only on
review discipline.

## Decision outcome

In the context of structured generation orchestration, facing boundary creep in
LangGraph nodes, Celery tasks, and durable checkpoint payloads, we decided for
dedicated Hecate groups plus structural checkpoint payload tests, and against a
single broad orchestration group or review-only convention, to achieve
deterministic import-boundary enforcement, accepting a more detailed
`pyproject.toml` group ordering and additional fixture maintenance.

The accepted groups are:

- `orchestration_nodes` for `episodic.orchestration._graph_nodes`, allowed to
depend on the `orchestration_checkpoint` DTO group and domain ports only.
- `orchestration` for graph builders, planning orchestration, and tool
execution policy, allowed to depend on application services, checkpoint DTOs,
and `orchestration_nodes`, but not adapters.
- `orchestration_tasks` for `episodic.worker.tasks`, allowed to depend on
domain services, domain ports, and `episodic.worker.workloads.WorkloadClass`.
- `orchestration_checkpoint` for checkpoint DTO and payload serialization
modules, allowed to depend on itself and domain-port value types only.

`episodic.worker.workloads.WorkloadClass` is the canonical domain-port-like
worker contract, so task modules can describe workload routing without
importing the Celery runtime. `episodic.worker.topology.WorkloadClass` remains
an explicit compatibility alias only.

## Consequences

### Positive

- `make lint` rejects adapter imports from LangGraph nodes, Celery tasks, and
checkpoint payload modules before review.
- The node/builder split keeps node functions small and easy to audit.
- Checkpoint payload DTOs are guarded by both Hecate and structural tests that
inspect field annotations.

### Negative

- Hecate group ordering now matters more. The dedicated
`orchestration_nodes` prefix must stay before the broader `orchestration` and
adapter prefixes.
- New orchestration fixtures must mirror production module prefixes closely or
they will not exercise the intended group.

### Neutral

- This decision does not change the public generation orchestration API.
- Durable checkpoint storage remains an outbound adapter that implements
`CheckpointPort`; it may import checkpoint DTOs to satisfy that port.

## References

See ADR-014 for the base Hecate adoption decision.[^1] See the orchestration
enforcement ExecPlan for the implementation milestones and validation
history.[^2]

[^1]: Hexagonal architecture enforcement:
`docs/adr/adr-014-hexagonal-architecture-enforcement.md`
[^2]: Orchestration enforcement ExecPlan:
`docs/execplans/2-4-5-extend-architecture-enforcement-to-orchestration-code.md`
4 changes: 4 additions & 0 deletions docs/contents.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ or delivery planning.
- source-intake upload storage and idempotency port decisions.
- [ADR 016: Adopt Skylos dead-code detection](adr/adr-016-adopt-skylos-dead-code-detection.md)
- blocking static dead-code detection and exception policy.
- [ADR 016: Orchestration architecture enforcement](adr/adr-016-orchestration-architecture-enforcement.md)
- LangGraph node, Celery task, and checkpoint payload enforcement decisions.
- [ADR 017: No-QA generation execution and TEI persistence][adr-017]
- generation launcher, draft persistence, recovery, and TEI retrieval
decisions.
Expand Down Expand Up @@ -162,6 +164,8 @@ or delivery planning.
- orchestration checkpoint plan.
- [Configure Celery queue routing](execplans/2-4-3-configure-celery-queue-routing.md)
- worker routing plan.
- [Extend architecture enforcement to orchestration code](execplans/2-4-5-extend-architecture-enforcement-to-orchestration-code.md)
- orchestration architecture enforcement plan.
- [LLM port adapter](execplans/3-2-1-llm-port-adapter.md) - large language
model adapter plan.
- [Introduce v1 target API prefix](execplans/4-1-1-introduce-v1-target-api-prefix.md)
Expand Down
52 changes: 44 additions & 8 deletions docs/developers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -788,13 +788,33 @@ The enforced groups are:
- `outbound_adapter`: SQLAlchemy storage, canonical ingestion adapters, and
OpenAI-compatible LLM adapters, including `episodic.llm.openai_adapter`, the
`episodic.llm.openai_api` helper package, and `episodic.llm.openai_client`.
- `orchestration_nodes`: LangGraph node functions under
`episodic.orchestration._graph_nodes`. This group may depend on the
`orchestration_checkpoint` DTO group and `domain_ports`, and must be ordered
before the broader `orchestration` group.
- `orchestration_checkpoint`: provider-neutral checkpoint payload DTO and
serialization modules.
- `orchestration`: LangGraph builders, graph state, planning orchestration, and
tool execution policy, excluding the dedicated node group. This group may
depend on `orchestration_nodes` because graph builders and the public facade
assemble and expose those nodes.
- `orchestration_tasks`: Celery task entrypoints.
- `composition_root`: modules that wire concrete adapters, currently
`episodic.api.runtime` and `episodic.worker.runtime`.

When adding a new port or adapter, update `[tool.hecate]` in `pyproject.toml`
in the same change as the package. Keep composition-root prefixes before
broader adapter prefixes because Hecate uses first-match group ordering. Add or
adjust fixture coverage in `tests/fixtures/architecture/` and run:
in the same change as the package. Keep specific prefixes before broader
prefixes because Hecate uses first-match group ordering: `composition_root`
before adapter prefixes, `orchestration_nodes` before the broad `orchestration`
prefix, and `orchestration_tasks` before worker adapter prefixes.

`episodic.worker.workloads.WorkloadClass` is the canonical worker workload
contract that task modules may import without pulling in the Celery app or
runtime wiring. `episodic.worker.topology.WorkloadClass` remains an explicit
compatibility alias only. Worker runtime modules own concrete Celery
configuration.

Add or adjust fixture coverage in `tests/fixtures/architecture/` and run:

```shell
uv run pytest -q tests/test_architecture_enforcement.py \
Expand All @@ -805,6 +825,13 @@ Port contract coverage lives in `tests/test_port_contracts.py`. Future
behavioural tests that exercise real `LLMPort` inference paths should use Vidai
Mock; structural conformance tests do not need an inference server.

For orchestration boundary fixtures, model the violating importer under the
same prefix Hecate will classify in production. Use
`orchestration/_graph_nodes.py` for node-only checks, `worker/tasks.py` for
Celery task checks, and `orchestration/_checkpoint_payload.py` for checkpoint
payload checks. Snapshot JSON diagnostics only after normalizing workspace
paths.

### TEI payload compression

Canonical TEI payload storage now supports transparent Zstandard compression
Expand Down Expand Up @@ -1406,8 +1433,13 @@ Roadmap item `2.4.1` introduces a dedicated orchestration package in

### Package structure

- `episodic/orchestration/_dto.py` contains the orchestration DTOs and shared
checkpoint DTOs.
- `episodic/orchestration/_dto.py` contains public request/config DTOs and
compatibility re-exports.
- `episodic/orchestration/_payload_dto.py` contains provider-neutral planner,
plan, and action-result payload DTOs.
- `episodic/orchestration/_checkpoint_dto.py` and
`episodic/orchestration/_checkpoint_payload.py` contain checkpoint state DTOs
and JSON payload serialization helpers.
- `episodic/orchestration/_protocols.py` contains the planner, executor,
checkpoint, and resume ports that keep graph policy independent of storage,
queue, and provider adapters.
Expand All @@ -1421,9 +1453,13 @@ Roadmap item `2.4.1` introduces a dedicated orchestration package in
`GuestBiosToolExecutor` implementation. It resolves the request's
`series_profile_id`, optional `episode_id`, and optional `template_id`
through the configured binding resolver before invoking the generation helper.
- `episodic/orchestration/langgraph.py` contains the in-process LangGraph path
used for `plan -> execute -> finish` and the checkpointing path that pauses
after planning.
- `episodic/orchestration/_graph_nodes.py` contains node functions that depend
on orchestration ports and DTOs only.
- `episodic/orchestration/_graph_builder.py` wires nodes, callbacks, and cost
recording into the compiled graph.
- `episodic/orchestration/langgraph.py` is the public graph facade for
`plan -> execute -> finish` and the checkpointing path that pauses after
planning.
- `episodic/orchestration/checkpoints.py` contains the in-memory checkpoint
adapter used by fast tests.
- `episodic/canonical/storage/workflow_checkpoints.py` contains the SQLAlchemy
Expand Down
29 changes: 20 additions & 9 deletions docs/episodic-podcast-generation-system-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Accepted decision records:
- [ADR 013: Speech synthesis adapters](adr/adr-013-speech-synthesis-adapters.md)
- [ADR 014: Hexagonal architecture enforcement](adr/adr-014-hexagonal-architecture-enforcement.md)
- [ADR 015: Upload and idempotency ports](adr/adr-015-upload-and-idempotency-ports.md)
- [ADR 016: Orchestration architecture enforcement](adr/adr-016-orchestration-architecture-enforcement.md)
- [ADR 018: Explicit repository-written versioning and history strategy](adr/adr-018-explicit-versioning-and-history-strategy.md)
- [ADR 019: Retrievable episode TEI revision history](adr/adr-019-episode-tei-revision-history.md)

Expand Down Expand Up @@ -118,14 +119,15 @@ Boundary rules:
domain and ports, but never on outbound adapter implementations.
- **Outbound adapters** (database, object storage, message broker, LLM/TTS
vendors) depend on the domain and ports, but never on inbound adapters.
- **Orchestration code** (LangGraph nodes and Celery tasks) will depend on
domain services and ports only; direct adapter access is reserved for the
later orchestration-specific enforcement slice.
- **Orchestration code** (LangGraph nodes and Celery tasks) depends on domain
services, ports, and provider-neutral orchestration DTOs only. Direct adapter
access is rejected by orchestration-specific Hecate groups.
- **Cross-adapter imports** are forbidden; interactions happen through ports or
well-defined message schemas.
- **Checkpoint payloads** should hold orchestration metadata; canonical domain
state is persisted through repositories rather than state blobs. Dedicated
checkpoint audits are part of the later orchestration enforcement slice.
- **Checkpoint payloads** hold orchestration metadata and JSON-shaped
provider-neutral DTOs; canonical domain state is persisted through
repositories rather than state blobs. Hecate grouping and structural tests
audit this boundary.

For screen readers: The following class diagram shows the module categories
used by the Hecate architecture checker, the allowed dependency directions
Expand Down Expand Up @@ -209,11 +211,13 @@ Enforcement mechanisms:
adherence as part of `make test`.
- The current Hecate policy covers canonical domain and port modules,
application services, Falcon and worker adapter seams, SQLAlchemy and LLM
outbound adapters, and explicit composition roots.
outbound adapters, explicit composition roots, LangGraph node modules, Celery
task modules, and orchestration checkpoint payload modules.
- Contract tests exercise port behaviour against adapter implementations, so
adapters are verified without coupling to infrastructure in the domain.
- Roadmap item `2.4.5` extends the same mechanism to LangGraph-node-specific
imports, Celery task policies, and checkpoint payload boundaries.
- Roadmap item `2.4.5` delivered LangGraph-node-specific imports, Celery task
policies, and checkpoint payload boundary enforcement. ADR-016 records the
orchestration-specific decisions.
- Code review checklists enforce idempotency keys, single-responsibility task
scope, and checkpoint payload audits for orchestration changes.

Expand All @@ -223,6 +227,13 @@ The following rules are normative for LangGraph nodes and Celery tasks:

- Orchestration code depends on domain services and ports only; adapters are
accessed exclusively through port interfaces.
- LangGraph node modules are classified separately from graph builders. Nodes
may depend on orchestration DTOs and ports, whilst builders and application
orchestration code may assemble domain services.
- Celery task modules depend on `WorkloadClass`, domain services, and ports;
worker runtime modules remain composition roots for concrete wiring.
- Checkpoint payload DTO modules are grouped before general orchestration
modules so Hecate's first-match ordering keeps them provider-neutral.
- Celery tasks are single-responsibility and idempotent, with idempotency keys
persisted per task or workflow step.
- Checkpoint payloads store orchestration metadata only; canonical domain data
Expand Down
Loading
Loading