refactor: name draft diagnostic codes

This commit is contained in:
lda
2026-06-28 03:06:17 +07:00 Verified
parent 8324a6b3f0
commit 58092966ee
3 changed files with 60 additions and 7 deletions
+5 -2
View File
@@ -14,6 +14,9 @@ from wf_core.models.schemas import NodeDef
from .models import WorkflowDraftWorkspace, summarize_draft_workspace from .models import WorkflowDraftWorkspace, summarize_draft_workspace
from .store import DraftWorkspaceConflictError, DraftWorkspaceStore from .store import DraftWorkspaceConflictError, DraftWorkspaceStore
WORKSPACE_EXISTS_CODE = "workspace_exists"
REVISION_CONFLICT_CODE = "revision_conflict"
JsonObject = dict[str, Any] JsonObject = dict[str, Any]
JsonPatch = list[dict[str, Any]] JsonPatch = list[dict[str, Any]]
NodeDefsForDraft = Callable[[JsonObject], Sequence[NodeDef]] NodeDefsForDraft = Callable[[JsonObject], Sequence[NodeDef]]
@@ -47,7 +50,7 @@ def create_draft_workspace(
except DraftWorkspaceConflictError as exc: except DraftWorkspaceConflictError as exc:
return _conflict_payload( return _conflict_payload(
exc.workspace, exc.workspace,
code="workspace_exists", code=WORKSPACE_EXISTS_CODE,
message=f"draft workspace {workspace_id!r} already exists", message=f"draft workspace {workspace_id!r} already exists",
) )
return summarize_draft_workspace(workspace) return summarize_draft_workspace(workspace)
@@ -139,7 +142,7 @@ def _revision_conflict_payload(
) -> JsonObject: ) -> JsonObject:
return _conflict_payload( return _conflict_payload(
workspace, workspace,
code="revision_conflict", code=REVISION_CONFLICT_CODE,
message=( message=(
f"workspace {workspace.id!r} is at revision " f"workspace {workspace.id!r} is at revision "
f"{workspace.revision}, not {expected_revision}" f"{workspace.revision}, not {expected_revision}"
+10 -5
View File
@@ -16,6 +16,11 @@ from wf_core.validation.issues import ValidationIssue, ValidationIssueCode
from .adapter import build_workflow_from_draft from .adapter import build_workflow_from_draft
from .models import WorkflowDraft from .models import WorkflowDraft
DRAFT_INVALID_CODE = "draft_invalid"
PATCH_INVALID_CODE = "patch_invalid"
DRAFT_NOT_OBJECT_CODE = "draft_not_object"
UNKNOWN_OUTCOME_CODE = "unknown_outcome"
JsonObject = dict[str, Any] JsonObject = dict[str, Any]
JsonPatch = list[dict[str, Any]] JsonPatch = list[dict[str, Any]]
OutcomeLookup = Callable[[str], tuple[str, ...] | None] OutcomeLookup = Callable[[str], tuple[str, ...] | None]
@@ -89,7 +94,7 @@ def patch_workflow_draft(
except Exception as exc: except Exception as exc:
return _invalid_result( return _invalid_result(
DraftDiagnostic( DraftDiagnostic(
code="patch_invalid", code=PATCH_INVALID_CODE,
path="patch", path="patch",
message=str(exc), message=str(exc),
) )
@@ -97,7 +102,7 @@ def patch_workflow_draft(
if not isinstance(patched, dict): if not isinstance(patched, dict):
return _invalid_result( return _invalid_result(
DraftDiagnostic( DraftDiagnostic(
code="draft_not_object", code=DRAFT_NOT_OBJECT_CODE,
path="", path="",
message="patched draft must be a JSON object", message="patched draft must be a JSON object",
) )
@@ -124,12 +129,12 @@ def _diagnostic_from_exception(exc: Exception) -> DraftDiagnostic:
if isinstance(exc, ValidationError): if isinstance(exc, ValidationError):
error = exc.errors()[0] error = exc.errors()[0]
return DraftDiagnostic( return DraftDiagnostic(
code="draft_invalid", code=DRAFT_INVALID_CODE,
path=_format_location(error["loc"]), path=_format_location(error["loc"]),
message=error["msg"], message=error["msg"],
) )
return DraftDiagnostic( return DraftDiagnostic(
code="draft_invalid", code=DRAFT_INVALID_CODE,
path="", path="",
message=str(exc), message=str(exc),
) )
@@ -237,7 +242,7 @@ def _validate_known_outcomes(
for outcome in route_map: for outcome in route_map:
if outcome not in known_outcomes: if outcome not in known_outcomes:
return DraftDiagnostic( return DraftDiagnostic(
code="unknown_outcome", code=UNKNOWN_OUTCOME_CODE,
path=f"routes.{step_id}.{outcome}", path=f"routes.{step_id}.{outcome}",
step_id=step_id, step_id=step_id,
message=( message=(
+45
View File
@@ -165,6 +165,51 @@ def test_explain_related_docs_do_not_point_to_planning_artifacts() -> None:
assert "docs/superpowers/" not in related_doc assert "docs/superpowers/" not in related_doc
def test_explain_registry_covers_core_validation_codes() -> None:
from wf_core.validation.issues import ValidationIssueCode
expected = {
ValidationIssueCode.INVALID_SOURCE_PATH.value,
ValidationIssueCode.INVALID_DESTINATION_PATH.value,
ValidationIssueCode.UNKNOWN_EDGE_DESTINATION.value,
ValidationIssueCode.UNDECLARED_EDGE_OUTCOME.value,
ValidationIssueCode.MISSING_OUTCOME_EDGE.value,
}
registry_codes = {
entry.code for entry in DEFAULT_EXPLAIN_REGISTRY.list_full_entries()
}
assert expected <= registry_codes
def test_explain_unknown_edge_destination_mentions_forward_route_repair() -> None:
card = DEFAULT_EXPLAIN_REGISTRY.get("unknown_edge_destination")
text = "\n".join(card.how_to_fix)
assert "wf draft handle" in text
assert "wf draft branch" in text
assert "target step first" in text.lower()
def test_explain_registry_uses_exported_draft_codes() -> None:
from wf_artifacts.draft_workspaces.api import REVISION_CONFLICT_CODE
from wf_artifacts.drafts.api import (
DRAFT_INVALID_CODE,
PATCH_INVALID_CODE,
UNKNOWN_OUTCOME_CODE,
)
registry_codes = {
entry.code for entry in DEFAULT_EXPLAIN_REGISTRY.list_full_entries()
}
assert DRAFT_INVALID_CODE in registry_codes
assert PATCH_INVALID_CODE in registry_codes
assert UNKNOWN_OUTCOME_CODE in registry_codes
assert REVISION_CONFLICT_CODE in registry_codes
def test_explain_related_doc_files_exist() -> None: def test_explain_related_doc_files_exist() -> None:
repo_root = Path(__file__).resolve().parents[2] repo_root = Path(__file__).resolve().parents[2]
for entry in DEFAULT_EXPLAIN_REGISTRY.list_full_entries(): for entry in DEFAULT_EXPLAIN_REGISTRY.list_full_entries():