be sure that it saves the new shape
This commit is contained in:
@@ -8,6 +8,16 @@
|
||||
|
||||
**Tech Stack:** Python 3.14, Pydantic v2, pytest, jsonschema, basedpyright, ruff.
|
||||
|
||||
**Current status as of 2026-05-20:** The implementation has moved past the
|
||||
original checklist. Typed path values, canonical node bindings, canonical
|
||||
runtime input/output handling, atomic state patches, canonical validation,
|
||||
JSON-Schema-native state reducers, schema validation, and authoring canonical
|
||||
emission are present in the tree. The remaining checklist item is the full
|
||||
compatibility/regression pass in Task 9. If future code changes touch this area,
|
||||
prefer adding focused tests to the existing `tests/core/test_*path*`,
|
||||
`tests/core/test_*mapping*`, and `tests/authoring/test_builder.py` coverage
|
||||
rather than reimplementing the earlier tasks.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
@@ -63,6 +63,40 @@ def test_workflow_artifact_can_be_marked_as_wrapper_intent() -> None:
|
||||
assert dumped["kind"] == "wrapper"
|
||||
|
||||
|
||||
def test_workflow_artifact_accepts_legacy_required_capability_map_and_dumps_list() -> (
|
||||
None
|
||||
):
|
||||
artifact = WorkflowArtifact.model_validate(
|
||||
{
|
||||
"id": "legacy_capabilities",
|
||||
"version": 1,
|
||||
"title": "Legacy Capabilities",
|
||||
"input_schema": {"type": "object", "properties": {}},
|
||||
"output_schema": {"type": "object", "properties": {}},
|
||||
"outcomes": ["done"],
|
||||
"plan": {"name": "legacy_capabilities", "nodes": [], "edges": []},
|
||||
"required_capabilities": {
|
||||
"demo.echo": {
|
||||
"kind": "tool",
|
||||
"input_schema_hash": "sha256:input",
|
||||
"output_schema_hash": "sha256:output",
|
||||
"observed_concrete_source": "demo.personal",
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
dumped = artifact.model_dump(mode="json")
|
||||
required = dumped["required_capabilities"][0]
|
||||
|
||||
assert isinstance(dumped["required_capabilities"], list)
|
||||
assert required["ref"] == "demo.echo"
|
||||
assert required["observed_concrete_source"] == "demo.personal"
|
||||
assert "logical_source" not in required
|
||||
assert "capability_name" not in required
|
||||
assert artifact.required_capability_map()["demo.echo"].logical_source == "demo"
|
||||
|
||||
|
||||
def test_workflow_deployment_binds_logical_sources_to_concrete_sources() -> None:
|
||||
deployment = WorkflowDeployment(
|
||||
id="summarize_docs.personal",
|
||||
@@ -85,6 +119,25 @@ def test_workflow_deployment_binds_logical_sources_to_concrete_sources() -> None
|
||||
assert deployment.binding_map()["context7"] == "context7.personal"
|
||||
|
||||
|
||||
def test_workflow_deployment_accepts_legacy_binding_map_and_dumps_list() -> None:
|
||||
deployment = WorkflowDeployment.model_validate(
|
||||
{
|
||||
"id": "legacy_bindings.personal",
|
||||
"artifact_id": "legacy_bindings",
|
||||
"artifact_version": 1,
|
||||
"bindings": {"demo": "demo.personal"},
|
||||
}
|
||||
)
|
||||
|
||||
dumped = deployment.model_dump(mode="json")
|
||||
binding = dumped["bindings"][0]
|
||||
|
||||
assert isinstance(dumped["bindings"], list)
|
||||
assert binding["logical_source"] == "demo"
|
||||
assert binding["concrete_source"] == "demo.personal"
|
||||
assert deployment.binding_map()["demo"] == "demo.personal"
|
||||
|
||||
|
||||
def test_dependency_diagnostic_is_structured() -> None:
|
||||
diagnostic = DependencyDiagnostic(
|
||||
severity=DiagnosticSeverity.ERROR,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
from wf_artifacts import (
|
||||
FileWorkflowArtifactStore,
|
||||
WorkflowArtifact,
|
||||
@@ -63,6 +65,72 @@ def test_file_store_round_trips_deployment(tmp_path) -> None:
|
||||
assert loaded.binding_map()["context7"] == "context7.personal"
|
||||
|
||||
|
||||
def test_file_store_loads_legacy_artifact_and_rewrites_canonical_shape(
|
||||
tmp_path,
|
||||
) -> None:
|
||||
store = FileWorkflowArtifactStore(tmp_path)
|
||||
artifact_dir = store.artifacts_dir / "legacy_capabilities"
|
||||
artifact_dir.mkdir(parents=True)
|
||||
artifact_path = artifact_dir / "1.json"
|
||||
artifact_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"id": "legacy_capabilities",
|
||||
"version": 1,
|
||||
"title": "Legacy Capabilities",
|
||||
"input_schema": {"type": "object", "properties": {}},
|
||||
"output_schema": {"type": "object", "properties": {}},
|
||||
"outcomes": ["done"],
|
||||
"plan": {"name": "legacy_capabilities", "nodes": [], "edges": []},
|
||||
"required_capabilities": {
|
||||
"demo.echo": {
|
||||
"kind": "tool",
|
||||
"input_schema_hash": "sha256:input",
|
||||
}
|
||||
},
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
loaded = store.get_artifact("legacy_capabilities", 1)
|
||||
store.save_artifact(loaded)
|
||||
rewritten = json.loads(artifact_path.read_text(encoding="utf-8"))
|
||||
|
||||
required = rewritten["required_capabilities"][0]
|
||||
assert required["ref"] == "demo.echo"
|
||||
assert required["kind"] == "tool"
|
||||
assert "logical_source" not in required
|
||||
assert "capability_name" not in required
|
||||
|
||||
|
||||
def test_file_store_loads_legacy_deployment_and_rewrites_canonical_shape(
|
||||
tmp_path,
|
||||
) -> None:
|
||||
store = FileWorkflowArtifactStore(tmp_path)
|
||||
deployment_path = store.deployments_dir / "legacy_bindings.personal.json"
|
||||
deployment_path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"id": "legacy_bindings.personal",
|
||||
"artifact_id": "legacy_bindings",
|
||||
"artifact_version": 1,
|
||||
"bindings": {"demo": "demo.personal"},
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
loaded = store.get_deployment("legacy_bindings.personal")
|
||||
store.save_deployment(loaded)
|
||||
rewritten = json.loads(deployment_path.read_text(encoding="utf-8"))
|
||||
|
||||
binding = rewritten["bindings"][0]
|
||||
assert binding["logical_source"] == "demo"
|
||||
assert binding["concrete_source"] == "demo.personal"
|
||||
assert loaded.binding_map()["demo"] == "demo.personal"
|
||||
|
||||
|
||||
def test_file_store_lists_deployments_in_id_order(tmp_path) -> None:
|
||||
store = FileWorkflowArtifactStore(tmp_path)
|
||||
store.save_deployment(
|
||||
|
||||
Reference in New Issue
Block a user