docs n + 1
This commit is contained in:
@@ -47,6 +47,8 @@ implementation state.
|
|||||||
hints, next actions, raw workflow plans, runtime dependencies, saved
|
hints, next actions, raw workflow plans, runtime dependencies, saved
|
||||||
subgraph preparation, and durable run lifecycle helpers. Old
|
subgraph preparation, and durable run lifecycle helpers. Old
|
||||||
`wf_mcp.workflow_surface` helper paths remain compatibility shims.
|
`wf_mcp.workflow_surface` helper paths remain compatibility shims.
|
||||||
|
- The boundary is documented in
|
||||||
|
[wf_api architecture](./wf_api_architecture.md).
|
||||||
|
|
||||||
## Active Next Roadmap
|
## Active Next Roadmap
|
||||||
|
|
||||||
@@ -59,9 +61,11 @@ implementation state.
|
|||||||
[2026-06-03 WorkflowOperationContext shape audit](./superpowers/research/2026-06-03-workflow-operation-context-audit.md).
|
[2026-06-03 WorkflowOperationContext shape audit](./superpowers/research/2026-06-03-workflow-operation-context-audit.md).
|
||||||
|
|
||||||
2. **Persisted run/resume spec**
|
2. **Persisted run/resume spec**
|
||||||
- Define the process-restart resume contract around run records, pinned
|
- Completed: the process-restart resume contract is defined in
|
||||||
deployment/artifact/subgraph environment, source/capability validation,
|
[2026-06-03 persisted run/resume contract](./superpowers/specs/2026-06-03-persisted-run-resume-contract.md).
|
||||||
trace paging, and interrupt-only pause semantics.
|
- It covers run records, pinned deployment/artifact/subgraph environment,
|
||||||
|
source/capability validation, trace paging, and interrupt-only pause
|
||||||
|
semantics.
|
||||||
- Keep ordinary dead tools/sources as diagnostics or failed runs, not implicit
|
- Keep ordinary dead tools/sources as diagnostics or failed runs, not implicit
|
||||||
pauses.
|
pauses.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,325 @@
|
|||||||
|
# Persisted Run/Resume Contract
|
||||||
|
|
||||||
|
Date: 2026-06-03
|
||||||
|
|
||||||
|
Status: contract clarification; current V1 mostly implemented
|
||||||
|
|
||||||
|
Related:
|
||||||
|
|
||||||
|
- [Durable workflow runs and resume design](./2026-05-26-durable-workflow-runs-and-resume-design.md)
|
||||||
|
- [Durable run operations](../../durable_run_operations.md)
|
||||||
|
- [WorkflowOperationContext audit](../research/2026-06-03-workflow-operation-context-audit.md)
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
This spec sharpens the public and internal contract for persisted deployment
|
||||||
|
runs. The older durable-run design describes the broad model and implemented V1.
|
||||||
|
This document defines the invariants that future MCP, CLI, and HTTP frontends
|
||||||
|
must preserve when starting, inspecting, tracing, and resuming stored runs.
|
||||||
|
|
||||||
|
The main rule: persisted resume is a human-in-the-loop interrupt mechanism, not
|
||||||
|
a generic retry/recovery mechanism for dead external sources.
|
||||||
|
|
||||||
|
## Contract Summary
|
||||||
|
|
||||||
|
- `run_deployment` creates a durable run only after deployment validation passes.
|
||||||
|
- Every started run receives a stable `run_id`.
|
||||||
|
- Stopped runs are persisted when execution returns `completed`, `failed`, or
|
||||||
|
`interrupted`.
|
||||||
|
- `resume_run` only resumes runs whose latest stored status is `interrupted`.
|
||||||
|
- Resume validates the pinned execution environment before mutating execution
|
||||||
|
state.
|
||||||
|
- If pinned dependency validation fails, resume returns `blocked` readiness and
|
||||||
|
does not consume the resume payload or write a new execution checkpoint.
|
||||||
|
- If a live tool/source fails during execution, the run fails. It is not paused.
|
||||||
|
- Trace entries are never returned wholesale by default; callers must request a
|
||||||
|
bounded range.
|
||||||
|
|
||||||
|
## Data Model Contract
|
||||||
|
|
||||||
|
### WorkflowRunRecord
|
||||||
|
|
||||||
|
`WorkflowRunRecord` is the durable summary for one started execution attempt.
|
||||||
|
|
||||||
|
Required invariants:
|
||||||
|
|
||||||
|
- `id` is a safe run id matching `RUN_ID_PATTERN`.
|
||||||
|
- `status` is one of `interrupted`, `completed`, or `failed`.
|
||||||
|
- `resume_readiness` is:
|
||||||
|
- `ready` for interrupted runs that are currently resumable.
|
||||||
|
- `blocked` for interrupted runs whose pinned dependency environment is
|
||||||
|
currently invalid.
|
||||||
|
- `not_applicable` for completed and failed runs.
|
||||||
|
- `environment` pins the exact deployment, root artifact, and child artifacts
|
||||||
|
captured at run start.
|
||||||
|
- `latest_checkpoint_id` points to the latest stored execution checkpoint.
|
||||||
|
- `diagnostics` stores control-plane diagnostics, especially blocked-resume
|
||||||
|
dependency diagnostics.
|
||||||
|
- `created_at` is stable for the run id.
|
||||||
|
- `updated_at` changes when the summary changes.
|
||||||
|
|
||||||
|
### RunCheckpoint
|
||||||
|
|
||||||
|
`RunCheckpoint` is the stored execution state at a public stopped boundary.
|
||||||
|
|
||||||
|
Required invariants:
|
||||||
|
|
||||||
|
- `run_id` matches the owning `WorkflowRunRecord.id`.
|
||||||
|
- `sequence` starts at `1` and increases monotonically per run.
|
||||||
|
- `reason` matches the stopped runtime status that caused checkpoint creation.
|
||||||
|
- `state` is a validated `PersistedRunState`, not an untyped dict.
|
||||||
|
- V1 writes checkpoints only when public run operations return stopped states.
|
||||||
|
|
||||||
|
### PinnedRunEnvironment
|
||||||
|
|
||||||
|
The pinned environment must be sufficient to resume without re-reading mutable
|
||||||
|
deployment or artifact definitions:
|
||||||
|
|
||||||
|
- `deployment`: exact deployment binding snapshot used at start.
|
||||||
|
- `root_artifact`: exact root artifact snapshot used at start.
|
||||||
|
- `child_artifacts`: exact saved child artifact snapshots used at start.
|
||||||
|
|
||||||
|
Changing or deleting a deployment after a run starts must not silently redirect
|
||||||
|
or erase that run's resume environment.
|
||||||
|
|
||||||
|
## Operation Contract
|
||||||
|
|
||||||
|
### `run_deployment`
|
||||||
|
|
||||||
|
Input:
|
||||||
|
|
||||||
|
- deployment id
|
||||||
|
- workflow input
|
||||||
|
- optional trace range
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
1. Load deployment and artifact from the configured artifact store.
|
||||||
|
2. Resolve saved child artifact tree.
|
||||||
|
3. Validate root and child dependency bindings against current available
|
||||||
|
sources.
|
||||||
|
4. If validation has blocking diagnostics:
|
||||||
|
- return `status="unrunnable"`
|
||||||
|
- return `run_id=None`
|
||||||
|
- do not create a run record
|
||||||
|
- do not write a checkpoint
|
||||||
|
5. If validation passes:
|
||||||
|
- create pinned environment
|
||||||
|
- execute workflow through `WorkflowRuntimeRunner`
|
||||||
|
- persist stopped run and checkpoint
|
||||||
|
- return compact run payload
|
||||||
|
|
||||||
|
Current implementation:
|
||||||
|
|
||||||
|
- `WorkflowRunApi.run_deployment()` follows this contract.
|
||||||
|
- `persist_stopped_run()` rejects active runtime statuses.
|
||||||
|
|
||||||
|
### `inspect_run`
|
||||||
|
|
||||||
|
Input:
|
||||||
|
|
||||||
|
- run id
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
1. Load `WorkflowRunRecord`.
|
||||||
|
2. Load latest checkpoint.
|
||||||
|
3. Decode checkpoint state into `RunState`.
|
||||||
|
4. Return compact summary:
|
||||||
|
- status
|
||||||
|
- run id
|
||||||
|
- resume readiness
|
||||||
|
- interrupt payload when present
|
||||||
|
- outcome/error/output when present
|
||||||
|
- diagnostics
|
||||||
|
- trace count
|
||||||
|
5. Do not return trace entries.
|
||||||
|
|
||||||
|
Current implementation:
|
||||||
|
|
||||||
|
- `WorkflowRunApi.inspect_run()` follows this contract.
|
||||||
|
|
||||||
|
### `read_run_trace`
|
||||||
|
|
||||||
|
Input:
|
||||||
|
|
||||||
|
- run id
|
||||||
|
- trace range with `start >= 0` and `limit > 0`
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
1. Validate trace range before store lookup.
|
||||||
|
2. Load run and latest checkpoint.
|
||||||
|
3. Return compact run summary plus the bounded trace slice.
|
||||||
|
4. Return trace metadata:
|
||||||
|
- `trace_start`
|
||||||
|
- `trace_limit`
|
||||||
|
- `trace_truncated`
|
||||||
|
- `trace_count`
|
||||||
|
|
||||||
|
Current implementation:
|
||||||
|
|
||||||
|
- `WorkflowRunApi.read_run_trace()` follows this contract.
|
||||||
|
|
||||||
|
### `resume_run`
|
||||||
|
|
||||||
|
Input:
|
||||||
|
|
||||||
|
- run id
|
||||||
|
- resume payload
|
||||||
|
- resume outcome, default `submitted`
|
||||||
|
- optional trace range
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
1. Load run and latest checkpoint.
|
||||||
|
2. Reject if stored run status is not `interrupted`.
|
||||||
|
3. Decode checkpoint state into `RunState`.
|
||||||
|
4. Validate pinned environment against current available sources.
|
||||||
|
5. If validation has blocking diagnostics:
|
||||||
|
- keep run status `interrupted`
|
||||||
|
- set `resume_readiness="blocked"`
|
||||||
|
- save updated run summary diagnostics
|
||||||
|
- do not write a new execution checkpoint
|
||||||
|
- do not apply resume payload
|
||||||
|
6. If validation passes:
|
||||||
|
- restore saved child artifact tree from pinned environment
|
||||||
|
- resume workflow through `WorkflowRuntimeRunner`
|
||||||
|
- persist next stopped run/checkpoint with same `run_id`
|
||||||
|
- return compact run payload
|
||||||
|
|
||||||
|
Current implementation:
|
||||||
|
|
||||||
|
- `WorkflowRunApi.resume_run()` follows this contract for stored interrupted
|
||||||
|
runs and blocked dependency validation.
|
||||||
|
- `restore_interrupted_run()` rejects non-interrupted statuses.
|
||||||
|
- `mark_resume_blocked()` updates run summary without writing a checkpoint.
|
||||||
|
|
||||||
|
## Status Semantics
|
||||||
|
|
||||||
|
| Condition | Public result |
|
||||||
|
| --- | --- |
|
||||||
|
| Deployment dependencies invalid before start | `status="unrunnable"`, no run id |
|
||||||
|
| Workflow reaches explicit interrupt | `status="interrupted"`, `resume_readiness="ready"` |
|
||||||
|
| Interrupted run has broken pinned dependency before resume | `status="interrupted"`, `resume_readiness="blocked"` |
|
||||||
|
| Workflow completes | `status="completed"`, `resume_readiness="not_applicable"` |
|
||||||
|
| Workflow/runtime/tool fails during execution | `status="failed"`, `resume_readiness="not_applicable"` |
|
||||||
|
|
||||||
|
`unrunnable` is not a stored run status. It is a pre-start response.
|
||||||
|
|
||||||
|
## External Source Failure Rule
|
||||||
|
|
||||||
|
External source failure during execution is not a resumable pause.
|
||||||
|
|
||||||
|
Rationale:
|
||||||
|
|
||||||
|
- A tool may have performed a side effect before disconnecting or failing to
|
||||||
|
return a response.
|
||||||
|
- Resuming from that point without explicit workflow semantics could duplicate
|
||||||
|
external side effects.
|
||||||
|
- Retry/timeout fields exist in models but are not yet an implemented runtime
|
||||||
|
policy.
|
||||||
|
|
||||||
|
Future retry support must explicitly define idempotency, unknown-side-effect
|
||||||
|
behavior, and checkpoint boundaries.
|
||||||
|
|
||||||
|
## Store Contract
|
||||||
|
|
||||||
|
`RunStore` must provide:
|
||||||
|
|
||||||
|
- save/get/list run records
|
||||||
|
- save/get/list checkpoints
|
||||||
|
- latest-checkpoint lookup
|
||||||
|
- safe run id validation
|
||||||
|
|
||||||
|
`FileRunStore` currently stores:
|
||||||
|
|
||||||
|
```text
|
||||||
|
<store-root>/runs/<run-id>/run.json
|
||||||
|
<store-root>/runs/<run-id>/checkpoints/000001.json
|
||||||
|
<store-root>/runs/<run-id>/checkpoints/000002.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Current limits:
|
||||||
|
|
||||||
|
- The file store uses per-process locking only.
|
||||||
|
- It is appropriate for local/dev/single-process use.
|
||||||
|
- A long-lived API or multi-worker deployment should use a transactional store
|
||||||
|
later.
|
||||||
|
|
||||||
|
## Frontend Contract
|
||||||
|
|
||||||
|
MCP, CLI, and future HTTP surfaces should preserve the same operation semantics:
|
||||||
|
|
||||||
|
- Start: `run_deployment`
|
||||||
|
- Inspect: `inspect_run`
|
||||||
|
- Debug trace: `read_run_trace`
|
||||||
|
- Continue explicit interrupt: `resume_run`
|
||||||
|
|
||||||
|
Frontend-specific names may differ, but they must not change:
|
||||||
|
|
||||||
|
- status meanings
|
||||||
|
- trace range requirement
|
||||||
|
- blocked resume behavior
|
||||||
|
- run id stability
|
||||||
|
- pinned environment semantics
|
||||||
|
- no-implicit-pause rule for dead tools/sources
|
||||||
|
|
||||||
|
## Current Gaps / Next Implementation Work
|
||||||
|
|
||||||
|
The core V1 behavior exists. Remaining implementation work should focus on
|
||||||
|
hardening and frontend durability:
|
||||||
|
|
||||||
|
1. **Required stores for durable API**
|
||||||
|
- Current `WorkflowOperationContext` allows optional stores for MCP test and
|
||||||
|
compatibility paths.
|
||||||
|
- A durable HTTP/API backend should construct a stricter context where
|
||||||
|
artifact, draft, and run stores are required.
|
||||||
|
|
||||||
|
2. **Run listing and checkpoint listing**
|
||||||
|
- `RunStore` can list runs/checkpoints, but the public workflow API does not
|
||||||
|
yet expose a mature paged run catalog.
|
||||||
|
- Add only after inspect/trace semantics remain compact and stable.
|
||||||
|
|
||||||
|
3. **Transactional backend**
|
||||||
|
- `FileRunStore` is fine for local process use.
|
||||||
|
- Multi-process/cloud use needs SQLite/Postgres or another transactional
|
||||||
|
store to avoid lost writes and weak concurrent resume behavior.
|
||||||
|
|
||||||
|
4. **Resume concurrency guard**
|
||||||
|
- Concurrent `resume_run` calls for the same interrupted run should not both
|
||||||
|
advance from the same checkpoint.
|
||||||
|
- V1 file store does not provide compare-and-swap semantics.
|
||||||
|
|
||||||
|
5. **Protocol-native long-running progress**
|
||||||
|
- MCP tasks/progress or an HTTP streaming/event surface should report active
|
||||||
|
long-running runs without bloating stopped-run responses.
|
||||||
|
|
||||||
|
6. **Retry/timeout policy**
|
||||||
|
- Do not activate existing retry/timeout fields casually.
|
||||||
|
- Specify idempotency and unknown-side-effect semantics first.
|
||||||
|
|
||||||
|
## Implementation Order
|
||||||
|
|
||||||
|
Recommended order after this contract:
|
||||||
|
|
||||||
|
1. Add tests that explicitly lock down the current contract where coverage is
|
||||||
|
weak:
|
||||||
|
- non-interrupted `resume_run` rejection
|
||||||
|
- blocked resume writes no checkpoint
|
||||||
|
- deleted deployment does not erase existing run inspection
|
||||||
|
- trace range validates before store lookup
|
||||||
|
2. Add a required-store context/factory for durable API surfaces.
|
||||||
|
3. Specify and implement a transactional run store backend when a cloud/API
|
||||||
|
deployment is real.
|
||||||
|
4. Add paged run listing/checkpoint listing only after the storage boundary is
|
||||||
|
stable.
|
||||||
|
|
||||||
|
## Non-Goals
|
||||||
|
|
||||||
|
- Do not redesign `RunState`.
|
||||||
|
- Do not checkpoint every node.
|
||||||
|
- Do not add automatic retry.
|
||||||
|
- Do not treat source death as an interrupt.
|
||||||
|
- Do not require MCP clients to reload dynamic tools to run workflows.
|
||||||
|
- Do not make HTTP/API design depend on `WfMcpService`.
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
# wf_api Architecture Boundary
|
||||||
|
|
||||||
|
`wf_api` is the process-local workflow application service layer. It is not just
|
||||||
|
a DTO wrapper around `wf_core`, and it is not an MCP transport package.
|
||||||
|
|
||||||
|
The package owns workflow-facing application operations that combine execution,
|
||||||
|
saved artifacts, deployment validation, authoring guidance, progressive payloads,
|
||||||
|
and run lifecycle policy into a stable API that CLI, MCP, and future HTTP
|
||||||
|
frontends can share.
|
||||||
|
|
||||||
|
## Responsibility Map
|
||||||
|
|
||||||
|
| Package | Responsibility |
|
||||||
|
| --- | --- |
|
||||||
|
| `wf_core` | Workflow execution semantics: graph models, runtime state, scheduler, path/state mapping, interrupts, subgraphs, foreach, and run-state codec. |
|
||||||
|
| `wf_artifacts` | Saved definitions and persistence contracts: workflow artifacts, deployments, draft workspaces, run records, checkpoints, artifact/deployment validation models. |
|
||||||
|
| `wf_platform` | Shared capability/source concepts and platform-facing contracts such as capability refs, source inventory models, documentation source models, and JSON schema helpers. |
|
||||||
|
| `wf_api` | Application workflows over core/artifacts/platform: capability discovery, wrapper hints, draft editing, artifact/deployment operations, run/resume operations, next actions, and progressive response shaping. |
|
||||||
|
| `wf_mcp` | MCP-specific transport, tool schemas, upstream MCP adapters, broker services, proxy/admin tools, config reload, and `WorkflowApi` context construction for MCP. |
|
||||||
|
| future `wf_http` | HTTP transport over `wf_api`, not a reimplementation of workflow business logic. |
|
||||||
|
| `wf_cli` | CLI frontend over `wf_api`; it may run locally against process-local stores or later target an HTTP backend. |
|
||||||
|
|
||||||
|
## What Belongs In wf_api
|
||||||
|
|
||||||
|
`wf_api` should contain code that is:
|
||||||
|
|
||||||
|
- protocol-neutral between MCP, CLI, and future HTTP
|
||||||
|
- workflow-application policy rather than low-level graph execution
|
||||||
|
- response shaping for human/LLM clients, such as compact list payloads and
|
||||||
|
bounded trace slices
|
||||||
|
- authoring guidance, such as wrapper hints and next actions
|
||||||
|
- orchestration across `wf_core`, `wf_artifacts`, and `wf_platform`
|
||||||
|
- durable run lifecycle policy over `RunStore` and `WorkflowRuntimeRunner`
|
||||||
|
|
||||||
|
Examples that belong in `wf_api`:
|
||||||
|
|
||||||
|
- `WorkflowApi`
|
||||||
|
- `WorkflowCapabilityApi`
|
||||||
|
- `WorkflowDraftApi`
|
||||||
|
- `WorkflowArtifactApi`
|
||||||
|
- `WorkflowDeploymentApi`
|
||||||
|
- `WorkflowRunApi`
|
||||||
|
- wrapper hints
|
||||||
|
- next actions
|
||||||
|
- runtime dependency resolution
|
||||||
|
- saved subgraph preparation helpers
|
||||||
|
- run lifecycle helpers such as `persist_stopped_run()` and
|
||||||
|
`validate_pinned_resume_environment()`
|
||||||
|
|
||||||
|
## What Does Not Belong In wf_api
|
||||||
|
|
||||||
|
`wf_api` must not contain:
|
||||||
|
|
||||||
|
- MCP SDK calls
|
||||||
|
- FastMCP tool/resource/prompt registration
|
||||||
|
- MCP content block models or MCP schema workarounds
|
||||||
|
- broker config file mutation
|
||||||
|
- upstream MCP session/runtime management
|
||||||
|
- proxy mounting or reload logic
|
||||||
|
- local process service construction that assumes `WfMcpService`
|
||||||
|
- scheduler/execution semantics that belong in `wf_core`
|
||||||
|
- persistence model definitions that belong in `wf_artifacts`
|
||||||
|
|
||||||
|
The hard import rule remains:
|
||||||
|
|
||||||
|
```text
|
||||||
|
wf_mcp -> wf_api is allowed
|
||||||
|
wf_api -> wf_mcp is forbidden
|
||||||
|
```
|
||||||
|
|
||||||
|
## WorkflowOperationContext
|
||||||
|
|
||||||
|
`WorkflowOperationContext` is the adapter seam that lets `wf_api` stay
|
||||||
|
transport-neutral.
|
||||||
|
|
||||||
|
Current shape:
|
||||||
|
|
||||||
|
```python
|
||||||
|
WorkflowOperationContext(
|
||||||
|
artifact_store=...,
|
||||||
|
draft_workspace_store=...,
|
||||||
|
run_store=...,
|
||||||
|
events=...,
|
||||||
|
specs=...,
|
||||||
|
runtime=...,
|
||||||
|
live_sources=...,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Important rules:
|
||||||
|
|
||||||
|
- Source inventory goes through `context.specs.capability_sources`.
|
||||||
|
- Qualified node lookup goes through `context.specs.get_qualified_spec()`.
|
||||||
|
- Runtime execution goes through `context.runtime`.
|
||||||
|
- Workflow events go through `context.events.record_workflow_event()`.
|
||||||
|
- Optional live source checks go through `context.live_sources`.
|
||||||
|
- Stores are still optional for MCP/test compatibility, but durable API
|
||||||
|
frontends should construct stricter contexts with required stores.
|
||||||
|
|
||||||
|
Do not add a catch-all `service` field to the context. If a domain API needs a
|
||||||
|
new dependency, add a narrow protocol or explicit field.
|
||||||
|
|
||||||
|
## Domain Services
|
||||||
|
|
||||||
|
`WorkflowApi` composes focused domain APIs:
|
||||||
|
|
||||||
|
```text
|
||||||
|
WorkflowApi
|
||||||
|
capabilities: WorkflowCapabilityApi
|
||||||
|
drafts: WorkflowDraftApi
|
||||||
|
artifacts: WorkflowArtifactApi
|
||||||
|
deployments: WorkflowDeploymentApi
|
||||||
|
runs: WorkflowRunApi
|
||||||
|
```
|
||||||
|
|
||||||
|
These domain services are allowed to return `dict[str, Any]` payloads because
|
||||||
|
they define application-facing response contracts consumed by multiple
|
||||||
|
frontends. Internally, they should prefer typed models from `wf_core`,
|
||||||
|
`wf_artifacts`, and `wf_platform`, then serialize at the boundary.
|
||||||
|
|
||||||
|
## Relationship To wf_core
|
||||||
|
|
||||||
|
`wf_core` is lower-level than `wf_api`.
|
||||||
|
|
||||||
|
`wf_api` may:
|
||||||
|
|
||||||
|
- compile or validate workflow-facing requests into core/artifact models
|
||||||
|
- call runtime runners that execute core workflows
|
||||||
|
- shape run traces and diagnostics for clients
|
||||||
|
|
||||||
|
`wf_api` must not:
|
||||||
|
|
||||||
|
- decide scheduler semantics
|
||||||
|
- mutate `RunState` internals directly
|
||||||
|
- add graph node semantics
|
||||||
|
- encode MCP/client-specific behavior into core execution
|
||||||
|
|
||||||
|
If a behavior changes how workflows execute, it probably belongs in `wf_core`
|
||||||
|
or in an explicit runtime dependency injected into `wf_core`, not in `wf_api`.
|
||||||
|
|
||||||
|
## Relationship To wf_artifacts
|
||||||
|
|
||||||
|
`wf_artifacts` owns durable definitions and storage contracts. `wf_api` owns
|
||||||
|
operations over them.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- `WorkflowArtifact`, `WorkflowDeployment`, `WorkflowRunRecord`, and
|
||||||
|
`RunCheckpoint` belong in `wf_artifacts`.
|
||||||
|
- `create_artifact_from_plan`, `save_deployment`, `run_deployment`, and
|
||||||
|
`resume_run` application flows belong in `wf_api`.
|
||||||
|
|
||||||
|
`wf_api` should not define parallel persistence models for the same durable
|
||||||
|
concepts. If a response needs a different shape, create response payload helpers
|
||||||
|
or next actions rather than duplicating the storage model.
|
||||||
|
|
||||||
|
## Relationship To wf_mcp
|
||||||
|
|
||||||
|
`wf_mcp` adapts MCP into `wf_api`.
|
||||||
|
|
||||||
|
Current MCP path:
|
||||||
|
|
||||||
|
```text
|
||||||
|
wf_mcp.workflow_surface.tools
|
||||||
|
-> WorkflowApi(context_from_service(service))
|
||||||
|
-> wf_api domain service
|
||||||
|
-> WorkflowOperationContext protocol
|
||||||
|
-> focused broker service / store / runtime implementation
|
||||||
|
```
|
||||||
|
|
||||||
|
MCP-specific concerns stay outside `wf_api`:
|
||||||
|
|
||||||
|
- tool schema names and safe tool names
|
||||||
|
- MCP resources/prompts-as-tools registration
|
||||||
|
- upstream MCP source liveness checks
|
||||||
|
- FastMCP notifications
|
||||||
|
- MCP content block normalization
|
||||||
|
- broker connection config/reload
|
||||||
|
|
||||||
|
## Future HTTP/API Boundary
|
||||||
|
|
||||||
|
A future HTTP API should reuse `WorkflowApi`, not copy MCP handlers.
|
||||||
|
|
||||||
|
Expected shape:
|
||||||
|
|
||||||
|
```text
|
||||||
|
wf_http route/controller
|
||||||
|
-> WorkflowApi(required_store_context)
|
||||||
|
-> wf_api domain services
|
||||||
|
```
|
||||||
|
|
||||||
|
The HTTP layer should own:
|
||||||
|
|
||||||
|
- request/response framework models
|
||||||
|
- auth/session policy
|
||||||
|
- API routing
|
||||||
|
- streaming/progress transport if needed
|
||||||
|
- construction of a durable `WorkflowOperationContext`
|
||||||
|
|
||||||
|
The HTTP layer should not own:
|
||||||
|
|
||||||
|
- workflow validation semantics
|
||||||
|
- run resume semantics
|
||||||
|
- wrapper hint policy
|
||||||
|
- deployment dependency validation
|
||||||
|
|
||||||
|
## Current Roadmap Implication
|
||||||
|
|
||||||
|
The next implementation work should follow this order:
|
||||||
|
|
||||||
|
1. Harden persisted run/resume contract tests in `wf_api`.
|
||||||
|
2. Introduce a stricter required-store context/factory for durable API surfaces.
|
||||||
|
3. Design the durable HTTP/API frontend around `WorkflowApi`.
|
||||||
|
4. Align CLI so it can target either local process stores or the future HTTP API.
|
||||||
|
|
||||||
|
Workflow primitives such as fork/gather and additional authoring sugar should
|
||||||
|
resume after the durability/platform boundary is stable.
|
||||||
@@ -60,6 +60,9 @@ New code should treat `wf_api.WorkflowApi` as the application-facing API. Do not
|
|||||||
add new callers that import `WorkflowSurfaceHandlers` directly unless they are
|
add new callers that import `WorkflowSurfaceHandlers` directly unless they are
|
||||||
compatibility tests.
|
compatibility tests.
|
||||||
|
|
||||||
|
The broader application-service boundary is documented in
|
||||||
|
[`wf_api_architecture.md`](wf_api_architecture.md).
|
||||||
|
|
||||||
This is a dependency-direction cleanup, not a full domain split. Most API
|
This is a dependency-direction cleanup, not a full domain split. Most API
|
||||||
methods still mirror the old workflow-surface payloads and return
|
methods still mirror the old workflow-surface payloads and return
|
||||||
`dict[str, Any]`.
|
`dict[str, Any]`.
|
||||||
|
|||||||
Reference in New Issue
Block a user