docs: archive completed implementation plans

This commit is contained in:
lda
2026-06-29 10:25:09 +07:00 Verified
parent 65ae699b42
commit 628fbbae7b
6 changed files with 73 additions and 1015 deletions
@@ -25,7 +25,7 @@
- Modify: `examples/agent_challenges/reports.py`
- Create: `tests/examples/test_agent_challenge_reports.py`
- [ ] **Step 1: Write a failing bounded-report test**
- [x] **Step 1: Write a failing bounded-report test**
Build a `_raw_result(tmp_path)` fixture matching the current V2 result shape,
including explicit paths, identity, challenge report, parsed text, metrics,
@@ -48,13 +48,13 @@ def test_trial_report_is_bounded_machine_projection(tmp_path: Path) -> None:
assert payload["manual_audit"]["status"] == "pending"
```
- [ ] **Step 2: Run and verify import failure**
- [x] **Step 2: Run and verify import failure**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py::test_trial_report_is_bounded_machine_projection -q
```
- [ ] **Step 3: Implement strict DTOs**
- [x] **Step 3: Implement strict DTOs**
Create `TrialIdentity`, `TrialOutcome`, `CommandToolBrief`, `TokenSummary`,
`AutomaticEvidence`, `ManualAuditSummary`, and `TrialReport` using
@@ -151,7 +151,7 @@ prompt hashes, raw path, and workspace path. Outcome holds task outcome,
validity, duration, return code, assertions, and parser errors. Evidence holds
bounded metrics, read categories, disallowed reads, and opaque commands.
- [ ] **Step 4: Implement the builder**
- [x] **Step 4: Implement the builder**
```python
def build_trial_report(
@@ -168,7 +168,7 @@ failure, output size/hash; exclude stdout/stderr/previews/metadata/full input.
Flag observable self-report conflicts. Treat example reads plus
`existing_solution=false` as a manual follow-up, not automatic guilt.
- [ ] **Step 5: Verify and commit**
- [x] **Step 5: Verify and commit**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py -q
@@ -182,19 +182,19 @@ git commit -m "feat: add normalized agent trial report model"
- Modify: `examples/agent_challenges/reports.py`
- Modify: `tests/examples/test_agent_challenge_reports.py`
- [ ] **Step 1: Add failing projection tests**
- [x] **Step 1: Add failing projection tests**
Assert writes to `workspace/final-report.md` and `results/trial.report.json`,
stable heading order, bounded commands, no raw outputs, pending audit, valid
JSON, and no temporary-file residue.
- [ ] **Step 2: Run and verify missing APIs**
- [x] **Step 2: Run and verify missing APIs**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py -k projection -q
```
- [ ] **Step 3: Implement Markdown renderer**
- [x] **Step 3: Implement Markdown renderer**
Use exactly these headings:
@@ -212,7 +212,7 @@ Use exactly these headings:
Render empty sections explicitly and commands as ordered bounded entries.
- [ ] **Step 4: Implement atomic writes**
- [x] **Step 4: Implement atomic writes**
```python
@dataclass(frozen=True, slots=True)
@@ -243,7 +243,7 @@ def write_trial_report_projections(
return TrialReportPaths(markdown=markdown_path, machine=machine_path)
```
- [ ] **Step 5: Verify and commit**
- [x] **Step 5: Verify and commit**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py -q
@@ -258,19 +258,19 @@ git commit -m "feat: write human and machine trial reports"
- Modify: `examples/agent_challenges/run_trials.py`
- Modify: `tests/examples/test_agent_challenge_harness_v2.py`
- [ ] **Step 1: Extend runner integration tests**
- [x] **Step 1: Extend runner integration tests**
For success and timeout, assert explicit `workspace_path`, `result_path`, and
`report_paths`; raw, Markdown, and machine files exist; machine challenge id is
correct; Markdown contains the final answer.
- [ ] **Step 2: Run and verify failure**
- [x] **Step 2: Run and verify failure**
```powershell
uv run pytest tests/examples/test_agent_challenge_harness_v2.py -k "runner_to_report or timeout" -q
```
- [ ] **Step 3: Add explicit paths before the single raw write**
- [x] **Step 3: Add explicit paths before the single raw write**
```python
"challenge_id": challenge.manifest.id,
@@ -285,17 +285,17 @@ uv run pytest tests/examples/test_agent_challenge_harness_v2.py -k "runner_to_re
Include `reads_by_category` in policy. Write raw result once before projection
generation; never rewrite it.
- [ ] **Step 4: Generate pending-audit projections**
- [x] **Step 4: Generate pending-audit projections**
Call `build_trial_report(result, audit=None)` and
`write_trial_report_projections`. On failure preserve raw evidence and return a
concise `report_generation_error`.
- [ ] **Step 5: Print report paths**
- [x] **Step 5: Print report paths**
Add `result_path` and `report_paths` to each central-runner summary.
- [ ] **Step 6: Verify and commit**
- [x] **Step 6: Verify and commit**
```powershell
uv run pytest tests/examples/test_agent_challenge_harness_v2.py -k "runner or timeout" -q
@@ -310,7 +310,7 @@ git commit -m "feat: generate reports after agent trials"
- Modify: `examples/agent_challenges/save_manual_audit.py`
- Modify: `tests/examples/test_agent_challenge_reports.py`
- [ ] **Step 1: Add failing regeneration test**
- [x] **Step 1: Add failing regeneration test**
```python
paths = save_v2_manual_audit(
@@ -326,18 +326,18 @@ paths = save_v2_manual_audit(
Assert YAML, JSON, and Markdown contain the official grade/corrections.
- [ ] **Step 2: Add invalid-audit preservation test**
- [x] **Step 2: Add invalid-audit preservation test**
Use outcome `maybe`, expect `ValueError`, and assert previous projections remain
byte-for-byte unchanged.
- [ ] **Step 3: Run and verify missing API**
- [x] **Step 3: Run and verify missing API**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py -k "manual_audit or invalid" -q
```
- [ ] **Step 4: Implement V2 audit writer**
- [x] **Step 4: Implement V2 audit writer**
Add:
@@ -367,13 +367,13 @@ Allow only `pass`, `fail`, `invalid`; require V2; use explicit raw paths;
validate before writes; atomically write audit; rebuild both projections; never
rewrite raw result.
- [ ] **Step 5: Route existing CLI by harness version**
- [x] **Step 5: Route existing CLI by harness version**
For V2, interpret `--manual-classification` as official outcome, reject
`--from-report`, and print JSON containing all three paths. Preserve referenced
V1 behavior.
- [ ] **Step 6: Verify and commit**
- [x] **Step 6: Verify and commit**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py -q
@@ -388,12 +388,12 @@ git commit -m "feat: regenerate trial reports after audit"
- Modify: `examples/agent_challenges/base-prompt.md`
- Modify: `tests/examples/test_agent_challenge_harness_v2.py`
- [ ] **Step 1: Add failing assertions**
- [x] **Step 1: Add failing assertions**
Assert the prompt mentions `tests/`, `examples/`, `read.product_code: true`,
`read.existing_solution: true`, and `read.adjacent_attempts: true`.
- [ ] **Step 2: Add approved paragraph**
- [x] **Step 2: Add approved paragraph**
```markdown
Files under `tests/` and `examples/` may contain complete or partial solutions.
@@ -402,7 +402,7 @@ If you inspect them, report `read.product_code: true`; also report
`read.adjacent_attempts: true` when they contain prior trial outputs.
```
- [ ] **Step 3: Verify and commit**
- [x] **Step 3: Verify and commit**
```powershell
uv run pytest tests/examples/test_agent_challenge_harness_v2.py -k base_prompt -q
@@ -416,7 +416,7 @@ git commit -m "docs: clarify challenge self-report rules"
- Modify: `docs/current_roadmap.md`
- Move this plan to `docs/historical/superpowers/plans/`.
- [ ] **Step 1: Run verification**
- [x] **Step 1: Run verification**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py tests/examples/test_agent_challenge_harness_v2.py tests/examples/test_agent_challenge_skill_bundle.py tests/examples/test_opencode_browser_click_challenge.py tests/examples/test_report_workflow_challenge.py -q
@@ -426,25 +426,25 @@ uv run basedpyright --level error examples/agent_challenges tests/examples/test_
git diff --check
```
- [ ] **Step 2: Smoke CLI help**
- [x] **Step 2: Smoke CLI help**
```powershell
uv run python examples/agent_challenges/run_trials.py --help
uv run python examples/agent_challenges/save_manual_audit.py --help
```
- [ ] **Step 3: Update roadmap and archive**
- [x] **Step 3: Update roadmap and archive**
Record completion, then move this plan to
`docs/historical/superpowers/plans/2026-06-23-agent-challenge-report-projections.md`.
- [ ] **Step 4: Review boundaries**
- [x] **Step 4: Review boundaries**
Confirm raw result is written once, machine report excludes raw outputs,
Markdown headings are stable, explicit paths are used, audit regenerates both,
V1 remains intact, and no runbook/branching challenge leaked into this slice.
- [ ] **Step 5: Commit completion docs**
- [x] **Step 5: Commit completion docs**
```powershell
git add docs/current_roadmap.md docs/superpowers/plans/2026-06-23-agent-challenge-report-projections.md docs/historical/superpowers/plans/2026-06-23-agent-challenge-report-projections.md
@@ -16,7 +16,7 @@
- Modify: `src/wf_core/paths.py`
- Test: `tests/core/test_path_values.py`
- [ ] **Step 1: Write failing parser and formatter tests**
- [x] **Step 1: Write failing parser and formatter tests**
Add tests proving quoted segments round-trip and roots remain typed:
@@ -36,13 +36,13 @@ def test_toml_path_strings_round_trip_literal_segments() -> None:
Also test `LocalPath.parse(".")`, bare keys, malformed TOML, invalid roots, and empty writable state paths.
- [ ] **Step 2: Run the focused test and verify RED**
- [x] **Step 2: Run the focused test and verify RED**
Run: `uv run pytest tests/core/test_path_values.py -q`
Expected: quoted full paths fail because current core parsing uses `str.split(".")`.
- [ ] **Step 3: Implement shared parsing and formatting**
- [x] **Step 3: Implement shared parsing and formatting**
In `src/wf_core/paths.py`, add the shared implementation:
@@ -102,13 +102,13 @@ LocalPath.__str__()
segment as the graph root. `StatePath` requires root `state` plus at least one
remaining segment. `LocalPath` has no serialized `local.` prefix.
- [ ] **Step 4: Run focused core tests**
- [x] **Step 4: Run focused core tests**
Run: `uv run pytest tests/core/test_path_values.py tests/core/test_nested_state_paths.py -q`
Expected: PASS.
- [ ] **Step 5: Commit**
- [x] **Step 5: Commit**
```bash
git add src/wf_core/paths.py tests/core/test_path_values.py
@@ -122,7 +122,7 @@ git commit -m "feat: define canonical TOML workflow paths"
- Modify: `tests/core/test_path_values.py`
- Modify: `tests/core/test_canonical_node_bindings.py`
- [ ] **Step 1: Write failing Pydantic projection tests**
- [x] **Step 1: Write failing Pydantic projection tests**
Extend the existing Pydantic path payload test:
@@ -144,13 +144,13 @@ def test_path_models_serialize_strings_but_accept_structural_compat() -> None:
assert PathPayload.model_json_schema()["properties"]["source"]["type"] == "string"
```
- [ ] **Step 2: Run tests and verify RED**
- [x] **Step 2: Run tests and verify RED**
Run: `uv run pytest tests/core/test_path_values.py tests/core/test_canonical_node_bindings.py -q`
Expected: current serializers emit `{root, parts}` objects.
- [ ] **Step 3: Change serializers and JSON schemas**
- [x] **Step 3: Change serializers and JSON schemas**
Make each path `_serialize` return `str(value)`. Replace the structural
`_path_json_schema` with a string schema whose description documents TOML-key
@@ -164,19 +164,19 @@ Keep a comment at the validator seam:
# New schemas and serializers expose the canonical TOML-key string form.
```
- [ ] **Step 4: Update exact serialized binding expectations**
- [x] **Step 4: Update exact serialized binding expectations**
Adjust tests that assert JSON payloads to expect strings such as
`input.message`, `state.echoed`, and `.`. Keep field-level assertions rather
than replacing whole large snapshots.
- [ ] **Step 5: Run core serialization tests**
- [x] **Step 5: Run core serialization tests**
Run: `uv run pytest tests/core/test_path_values.py tests/core/test_canonical_node_bindings.py tests/core/test_run_codec.py -q`
Expected: PASS, including decoding old structural path objects.
- [ ] **Step 6: Commit**
- [x] **Step 6: Commit**
```bash
git add src/wf_core/paths.py tests/core/test_path_values.py tests/core/test_canonical_node_bindings.py
@@ -189,7 +189,7 @@ git commit -m "feat: serialize canonical workflow path strings"
- Modify: `src/wf_authoring/dsl/path_inputs.py`
- Modify: `tests/authoring/test_path_inputs.py`
- [ ] **Step 1: Add delegation coverage**
- [x] **Step 1: Add delegation coverage**
Add a test proving full rooted strings and explicit-root expressions resolve to
the same structured value:
@@ -204,19 +204,19 @@ def test_authoring_paths_share_core_toml_grammar() -> None:
)
```
- [ ] **Step 2: Replace `_parse_toml_key_expr`**
- [x] **Step 2: Replace `_parse_toml_key_expr`**
Delete the local `tomllib` parser and import
`parse_toml_path_segments` from `wf_core.paths`. Preserve iterable and
structural-object coercion behavior for Python callers.
- [ ] **Step 3: Run authoring tests**
- [x] **Step 3: Run authoring tests**
Run: `uv run pytest tests/authoring/test_path_inputs.py tests/authoring/test_builder.py tests/authoring/test_conditions.py -q`
Expected: PASS.
- [ ] **Step 4: Commit**
- [x] **Step 4: Commit**
```bash
git add src/wf_authoring/dsl/path_inputs.py tests/authoring/test_path_inputs.py
@@ -231,19 +231,19 @@ git commit -m "refactor: share workflow path grammar"
- Modify: `tests/wf_transport_rpc_http/test_client.py`
- Modify: `tests/wf_mcp/workflow_surface/test_drafts.py`
- [ ] **Step 1: Add one stored-draft compatibility regression**
- [x] **Step 1: Add one stored-draft compatibility regression**
Create a workspace from a draft containing structural path objects, retrieve or
patch it, and assert the next serialized draft uses canonical strings while
preserving the same path values.
- [ ] **Step 2: Update focused transport assertions**
- [x] **Step 2: Update focused transport assertions**
Change only assertions for serialized path fields. RPC and MCP requests should
advertise and return strings; input model tests must still accept structural
objects.
- [ ] **Step 3: Run affected suites**
- [x] **Step 3: Run affected suites**
Run:
@@ -253,7 +253,7 @@ uv run pytest tests/wf_api/test_drafts_service.py tests/wf_transport_rpc_http/te
Expected: PASS.
- [ ] **Step 4: Commit**
- [x] **Step 4: Commit**
```bash
git add tests/wf_api/test_drafts_service.py tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_http/test_client.py tests/wf_mcp/workflow_surface/test_drafts.py
@@ -272,7 +272,7 @@ git commit -m "test: cover canonical path transport compatibility"
- Modify: `docs/superpowers/specs/2026-06-27-draft-semantic-authoring-boundary.md`
- Move after completion: `docs/superpowers/plans/2026-06-27-canonical-toml-path-strings.md` -> `docs/historical/superpowers/plans/2026-06-27-canonical-toml-path-strings.md`
- [ ] **Step 1: Replace structural path examples**
- [x] **Step 1: Replace structural path examples**
Use canonical examples:
@@ -284,12 +284,12 @@ Use canonical examples:
Document TOML quoting with `state."field.with.dot"`. State that structural
objects are input-only compatibility and must not be generated by agents.
- [ ] **Step 2: Record implementation status**
- [x] **Step 2: Record implementation status**
Mark the canonical-path section implemented in the design spec and add a short
completed roadmap entry.
- [ ] **Step 3: Run verification**
- [x] **Step 3: Run verification**
```bash
uv run pytest tests/core/test_path_values.py tests/core/test_canonical_node_bindings.py tests/authoring/test_path_inputs.py tests/authoring/test_builder.py tests/wf_api/test_drafts_service.py tests/wf_transport_rpc_http/test_app.py tests/wf_transport_rpc_http/test_client.py tests/wf_mcp/workflow_surface/test_drafts.py -q
@@ -302,7 +302,7 @@ git diff --check
Expected: all tests pass, Ruff is clean, basedpyright reports zero errors, and
`git diff --check` reports no whitespace errors.
- [ ] **Step 4: Archive and commit the plan**
- [x] **Step 4: Archive and commit the plan**
```bash
git mv docs/superpowers/plans/2026-06-27-canonical-toml-path-strings.md docs/historical/superpowers/plans/2026-06-27-canonical-toml-path-strings.md
@@ -8,7 +8,7 @@
**Tech Stack:** Python 3.14, Pydantic v2, JSON Patch, Typer, JSON-RPC, FastMCP, pytest, Ruff, basedpyright.
**Prerequisite:** Complete `docs/superpowers/plans/2026-06-27-canonical-toml-path-strings.md` first.
**Prerequisite:** Complete `docs/historical/superpowers/plans/2026-06-27-canonical-toml-path-strings.md` first.
---
@@ -27,7 +27,7 @@
- Modify: `src/wf_artifacts/draft_workspaces/api.py`
- Test: `tests/wf_cli/test_explain.py`
- [ ] **Step 1: Write the failing import test**
- [x] **Step 1: Write the failing import test**
Add this test to `tests/wf_cli/test_explain.py`:
@@ -50,7 +50,7 @@ def test_explain_registry_uses_exported_draft_codes() -> None:
assert REVISION_CONFLICT_CODE in registry_codes
```
- [ ] **Step 2: Run the test and verify RED**
- [x] **Step 2: Run the test and verify RED**
Run:
@@ -60,7 +60,7 @@ uv run pytest tests/wf_cli/test_explain.py::test_explain_registry_uses_exported_
Expected: import failure for the new constants.
- [ ] **Step 3: Add exported constants near producers**
- [x] **Step 3: Add exported constants near producers**
In `src/wf_artifacts/drafts/api.py`, near the type aliases, add:
@@ -94,7 +94,7 @@ code=WORKSPACE_EXISTS_CODE
code=REVISION_CONFLICT_CODE
```
- [ ] **Step 4: Run the focused test and verify it now reaches registry failure**
- [x] **Step 4: Run the focused test and verify it now reaches registry failure**
Run:
@@ -104,7 +104,7 @@ uv run pytest tests/wf_cli/test_explain.py::test_explain_registry_uses_exported_
Expected: failure because the registry does not yet contain the new codes.
- [ ] **Step 5: Commit**
- [x] **Step 5: Commit**
```powershell
git add src/wf_artifacts/drafts/api.py src/wf_artifacts/draft_workspaces/api.py tests/wf_cli/test_explain.py
@@ -117,7 +117,7 @@ git commit -m "refactor: name draft diagnostic codes"
- Modify: `src/wf_cli/explain/entries.py`
- Modify: `tests/wf_cli/test_explain.py`
- [ ] **Step 1: Write failing tests for workflow validation cards**
- [x] **Step 1: Write failing tests for workflow validation cards**
Add this test to `tests/wf_cli/test_explain.py`:
@@ -152,7 +152,7 @@ def test_explain_unknown_edge_destination_mentions_forward_route_repair() -> Non
assert "target step first" in text.lower()
```
- [ ] **Step 2: Run tests and verify RED**
- [x] **Step 2: Run tests and verify RED**
Run:
@@ -162,7 +162,7 @@ uv run pytest tests/wf_cli/test_explain.py::test_explain_registry_covers_core_va
Expected: unknown code / missing registry entries.
- [ ] **Step 3: Import real code sources**
- [x] **Step 3: Import real code sources**
At the top of `src/wf_cli/explain/entries.py`, add:
@@ -176,7 +176,7 @@ from wf_artifacts.drafts.api import (
from wf_core.validation.issues import ValidationIssueCode
```
- [ ] **Step 4: Add the new cards**
- [x] **Step 4: Add the new cards**
Append these `ExplainCard` entries to `EXPLAIN_CARDS`:
@@ -354,7 +354,7 @@ ExplainCard(
),
```
- [ ] **Step 5: Run explain tests**
- [x] **Step 5: Run explain tests**
Run:
@@ -364,7 +364,7 @@ uv run pytest tests/wf_cli/test_explain.py -q
Expected: PASS.
- [ ] **Step 6: Commit**
- [x] **Step 6: Commit**
```powershell
git add src/wf_cli/explain/entries.py tests/wf_cli/test_explain.py
@@ -379,7 +379,7 @@ git commit -m "feat: explain draft validation codes"
- Modify: `skills/wf-workflow/references/troubleshooting.md`
- Modify: `docs/current_roadmap.md`
- [ ] **Step 1: Update docs**
- [x] **Step 1: Update docs**
In `docs/wf_cli.md`, under `## Explain`, add a short list of draft examples:
@@ -409,7 +409,7 @@ In `skills/wf-workflow/references/troubleshooting.md`, add:
step or repair the route; do not guess `draft step add` or `draft export`.
```
- [ ] **Step 2: Update roadmap**
- [x] **Step 2: Update roadmap**
Add a completed bullet under Priority 1:
@@ -418,7 +418,7 @@ Add a completed bullet under Priority 1:
`unknown_edge_destination`, `invalid_source_path`, and `patch_invalid`.
```
- [ ] **Step 3: Verify docs and skills**
- [x] **Step 3: Verify docs and skills**
Run:
@@ -430,7 +430,7 @@ uv run basedpyright --level error src/wf_cli/explain/entries.py tests/wf_cli/tes
Expected: all pass.
- [ ] **Step 4: Commit**
- [x] **Step 4: Commit**
```powershell
git add docs/wf_cli.md skills/wf-cli/SKILL.md skills/wf-workflow/references/troubleshooting.md docs/current_roadmap.md
@@ -443,7 +443,7 @@ git commit -m "docs: teach draft explain codes"
- Move: `docs/superpowers/plans/2026-06-28-explain-draft-diagnostics.md`
- Modify: `docs/current_roadmap.md`
- [ ] **Step 1: Smoke the CLI**
- [x] **Step 1: Smoke the CLI**
Run:
@@ -455,7 +455,7 @@ uv run wf explain --list --format compact
Expected: each command exits 0 and prints useful text.
- [ ] **Step 2: Archive the plan**
- [x] **Step 2: Archive the plan**
Move this plan to:
@@ -463,7 +463,7 @@ Move this plan to:
docs/historical/superpowers/plans/2026-06-28-explain-draft-diagnostics.md
```
- [ ] **Step 3: Run final checks**
- [x] **Step 3: Run final checks**
Run:
@@ -476,7 +476,7 @@ uv run basedpyright --level error src/wf_cli/explain/entries.py tests/wf_cli/tes
Expected: all pass.
- [ ] **Step 4: Commit**
- [x] **Step 4: Commit**
```powershell
git add docs/current_roadmap.md docs/historical/superpowers/plans/2026-06-28-explain-draft-diagnostics.md
@@ -1,452 +0,0 @@
# Agent Challenge Report Projections Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Generate equivalent bounded Markdown and JSON reports for every V2 trial and regenerate both after audit without mutating raw evidence.
**Architecture:** Add strict Pydantic report DTOs, project one `TrialReport` to Markdown and JSON, wire projection generation after raw result persistence, and make V2 audit rebuild both. Preserve referenced V1 behavior.
**Tech Stack:** Python 3.14, Pydantic v2, PyYAML, pathlib, argparse, pytest, Ruff, basedpyright.
---
## File Structure
- Create `examples/agent_challenges/report_models.py`.
- Modify `examples/agent_challenges/reports.py`, `runner.py`, `run_trials.py`, `audit.py`, and `base-prompt.md`.
- Create `tests/examples/test_agent_challenge_reports.py`.
- Modify `tests/examples/test_agent_challenge_harness_v2.py`.
- Update `docs/current_roadmap.md` and archive this plan.
### Task 1: Define The Normalized Report
**Files:**
- Create: `examples/agent_challenges/report_models.py`
- Modify: `examples/agent_challenges/reports.py`
- Create: `tests/examples/test_agent_challenge_reports.py`
- [ ] **Step 1: Write a failing bounded-report test**
Build a `_raw_result(tmp_path)` fixture matching the current V2 result shape,
including explicit paths, identity, challenge report, parsed text, metrics,
policy, tool calls, and deliberately large stdout/output previews.
```python
def test_trial_report_is_bounded_machine_projection(tmp_path: Path) -> None:
payload = build_trial_report(_raw_result(tmp_path), audit=None).model_dump(
mode="json"
)
assert payload["schema_version"] == 1
assert payload["identity"]["challenge_id"] == "fixture"
assert payload["outcome"]["task_outcome"] == "success"
assert payload["commands_and_tools"][0]["detail"].endswith(
"workflow.plan.json"
)
serialized = json.dumps(payload)
assert "large raw stream" not in serialized
assert "full tool output" not in serialized
assert payload["manual_audit"]["status"] == "pending"
```
- [ ] **Step 2: Run and verify import failure**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py::test_trial_report_is_bounded_machine_projection -q
```
- [ ] **Step 3: Implement strict DTOs**
Create `TrialIdentity`, `TrialOutcome`, `CommandToolBrief`, `TokenSummary`,
`AutomaticEvidence`, `ManualAuditSummary`, and `TrialReport` using
`ConfigDict(extra="forbid")`.
```python
class StrictReportModel(BaseModel):
model_config = ConfigDict(extra="forbid")
class TrialIdentity(StrictReportModel):
challenge_id: str
model: str
variant: str
instruction_profile: str
trial_index: int
repository_commit: str | None = None
repository_dirty: bool | None = None
prompt_hashes: dict[str, str] = Field(default_factory=dict)
raw_result_path: str
workspace_path: str
class TrialOutcome(StrictReportModel):
task_outcome: str
evaluation_validity: str
duration_seconds: float
returncode: int | None
assertion_failures: list[str] = Field(default_factory=list)
parse_errors: dict[str, dict[str, str]] = Field(default_factory=dict)
class CommandToolBrief(StrictReportModel):
ordinal: int
tool: str
status: str
title: str
detail: str | None = None
failed: bool
output_chars: int
output_sha256: str
class TokenSummary(StrictReportModel):
total: int = 0
input: int = 0
output: int = 0
reasoning: int = 0
cache_read: int = 0
cache_write: int = 0
class AutomaticEvidence(StrictReportModel):
step_count: int = 0
tool_call_count: int = 0
failed_tool_call_count: int = 0
tool_counts: dict[str, int] = Field(default_factory=dict)
tokens: TokenSummary = Field(default_factory=TokenSummary)
cost: float = 0.0
unknown_event_count: int = 0
reads_by_category: dict[str, list[str]] = Field(default_factory=dict)
escalated_to_product_code: bool = False
disallowed_reads: list[str] = Field(default_factory=list)
opaque_shell_commands: list[str] = Field(default_factory=list)
class ManualAuditSummary(StrictReportModel):
status: Literal["pending", "complete"] = "pending"
official_outcome: str | None = None
auditor: str | None = None
audited_at: str | None = None
corrections: list[str] = Field(default_factory=list)
notes: str = ""
read_flags: dict[str, bool] = Field(default_factory=dict)
evidence: dict[str, Any] = Field(default_factory=dict)
class TrialReport(StrictReportModel):
schema_version: Literal[1] = 1
identity: TrialIdentity
outcome: TrialOutcome
agent_self_report: dict[str, Any] | None = None
final_agent_answer: str | None = None
commands_and_tools: list[CommandToolBrief] = Field(default_factory=list)
automatic_evidence: AutomaticEvidence
policy_findings: list[str] = Field(default_factory=list)
self_report_discrepancies: list[str] = Field(default_factory=list)
manual_audit: ManualAuditSummary = Field(default_factory=ManualAuditSummary)
follow_up_notes: list[str] = Field(default_factory=list)
```
Identity holds challenge/model/variant/profile/index, repository provenance,
prompt hashes, raw path, and workspace path. Outcome holds task outcome,
validity, duration, return code, assertions, and parser errors. Evidence holds
bounded metrics, read categories, disallowed reads, and opaque commands.
- [ ] **Step 4: Implement the builder**
```python
def build_trial_report(
result: dict[str, object],
*,
audit: dict[str, object] | None,
) -> TrialReport:
"""Project immutable raw evidence and optional audit into one report."""
```
Use focused helpers. Require explicit paths; bound final text to 8,000 chars and
command detail to 1,000; retain only tool ordinal/name/status/title/detail,
failure, output size/hash; exclude stdout/stderr/previews/metadata/full input.
Flag observable self-report conflicts. Treat example reads plus
`existing_solution=false` as a manual follow-up, not automatic guilt.
- [ ] **Step 5: Verify and commit**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py -q
git add examples/agent_challenges/report_models.py examples/agent_challenges/reports.py tests/examples/test_agent_challenge_reports.py
git commit -m "feat: add normalized agent trial report model"
```
### Task 2: Render And Write Both Projections
**Files:**
- Modify: `examples/agent_challenges/reports.py`
- Modify: `tests/examples/test_agent_challenge_reports.py`
- [ ] **Step 1: Add failing projection tests**
Assert writes to `workspace/final-report.md` and `results/trial.report.json`,
stable heading order, bounded commands, no raw outputs, pending audit, valid
JSON, and no temporary-file residue.
- [ ] **Step 2: Run and verify missing APIs**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py -k projection -q
```
- [ ] **Step 3: Implement Markdown renderer**
Use exactly these headings:
```markdown
# Trial Report
## Outcome
## Agent Self-Report
## Commands And Tool Calls
## Automatic Evidence
## Policy Findings
## Self-Report Discrepancies
## Manual Audit
## Follow-Up Notes
```
Render empty sections explicitly and commands as ordered bounded entries.
- [ ] **Step 4: Implement atomic writes**
```python
@dataclass(frozen=True, slots=True)
class TrialReportPaths:
markdown: Path
machine: Path
def _atomic_write_text(path: Path, text: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_name(f".{path.name}.tmp")
temporary.write_text(text, encoding="utf-8")
temporary.replace(path)
def write_trial_report_projections(
report: TrialReport,
*,
markdown_path: Path,
machine_path: Path,
) -> TrialReportPaths:
machine = json.dumps(
report.model_dump(mode="json"), indent=2, sort_keys=True
) + "\n"
markdown = render_trial_report_markdown(report).rstrip() + "\n"
_atomic_write_text(machine_path, machine)
_atomic_write_text(markdown_path, markdown)
return TrialReportPaths(markdown=markdown_path, machine=machine_path)
```
- [ ] **Step 5: Verify and commit**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py -q
git add examples/agent_challenges/reports.py tests/examples/test_agent_challenge_reports.py
git commit -m "feat: write human and machine trial reports"
```
### Task 3: Generate Reports From The Runner
**Files:**
- Modify: `examples/agent_challenges/runner.py`
- Modify: `examples/agent_challenges/run_trials.py`
- Modify: `tests/examples/test_agent_challenge_harness_v2.py`
- [ ] **Step 1: Extend runner integration tests**
For success and timeout, assert explicit `workspace_path`, `result_path`, and
`report_paths`; raw, Markdown, and machine files exist; machine challenge id is
correct; Markdown contains the final answer.
- [ ] **Step 2: Run and verify failure**
```powershell
uv run pytest tests/examples/test_agent_challenge_harness_v2.py -k "runner_to_report or timeout" -q
```
- [ ] **Step 3: Add explicit paths before the single raw write**
```python
"challenge_id": challenge.manifest.id,
"workspace_path": str(workspace.root.resolve()),
"result_path": str(result_path.resolve()),
"report_paths": {
"markdown": str((workspace.root / "final-report.md").resolve()),
"machine": str(result_path.with_suffix(".report.json").resolve()),
},
```
Include `reads_by_category` in policy. Write raw result once before projection
generation; never rewrite it.
- [ ] **Step 4: Generate pending-audit projections**
Call `build_trial_report(result, audit=None)` and
`write_trial_report_projections`. On failure preserve raw evidence and return a
concise `report_generation_error`.
- [ ] **Step 5: Print report paths**
Add `result_path` and `report_paths` to each central-runner summary.
- [ ] **Step 6: Verify and commit**
```powershell
uv run pytest tests/examples/test_agent_challenge_harness_v2.py -k "runner or timeout" -q
git add examples/agent_challenges/runner.py examples/agent_challenges/run_trials.py tests/examples/test_agent_challenge_harness_v2.py
git commit -m "feat: generate reports after agent trials"
```
### Task 4: Regenerate Reports After Manual Audit
**Files:**
- Modify: `examples/agent_challenges/audit.py`
- Modify: `examples/agent_challenges/save_manual_audit.py`
- Modify: `tests/examples/test_agent_challenge_reports.py`
- [ ] **Step 1: Add failing regeneration test**
```python
paths = save_v2_manual_audit(
result_path,
official_outcome="pass",
auditor="reviewer",
audited_at="2026-06-23T00:00:00Z",
read_overrides={"existing_solution": True},
corrections=["Agent inspected a ready-made workflow plan."],
notes="Technical run passed; self-report corrected.",
)
```
Assert YAML, JSON, and Markdown contain the official grade/corrections.
- [ ] **Step 2: Add invalid-audit preservation test**
Use outcome `maybe`, expect `ValueError`, and assert previous projections remain
byte-for-byte unchanged.
- [ ] **Step 3: Run and verify missing API**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py -k "manual_audit or invalid" -q
```
- [ ] **Step 4: Implement V2 audit writer**
Add:
```python
@dataclass(frozen=True, slots=True)
class V2AuditPaths:
audit: Path
markdown: Path
machine: Path
def save_v2_manual_audit(
result_path: Path,
*,
official_outcome: str,
auditor: str = "human",
audited_at: str | None = None,
read_overrides: dict[str, bool] | None = None,
evidence_overrides: dict[str, object] | None = None,
corrections: list[str] | None = None,
notes: str = "",
) -> V2AuditPaths:
"""Write authoritative audit data and regenerate both report projections."""
```
Allow only `pass`, `fail`, `invalid`; require V2; use explicit raw paths;
validate before writes; atomically write audit; rebuild both projections; never
rewrite raw result.
- [ ] **Step 5: Route existing CLI by harness version**
For V2, interpret `--manual-classification` as official outcome, reject
`--from-report`, and print JSON containing all three paths. Preserve referenced
V1 behavior.
- [ ] **Step 6: Verify and commit**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py -q
uv run python examples/agent_challenges/save_manual_audit.py --help
git add examples/agent_challenges/audit.py examples/agent_challenges/save_manual_audit.py tests/examples/test_agent_challenge_reports.py
git commit -m "feat: regenerate trial reports after audit"
```
### Task 5: Clarify Shared Self-Reporting Rules
**Files:**
- Modify: `examples/agent_challenges/base-prompt.md`
- Modify: `tests/examples/test_agent_challenge_harness_v2.py`
- [ ] **Step 1: Add failing assertions**
Assert the prompt mentions `tests/`, `examples/`, `read.product_code: true`,
`read.existing_solution: true`, and `read.adjacent_attempts: true`.
- [ ] **Step 2: Add approved paragraph**
```markdown
Files under `tests/` and `examples/` may contain complete or partial solutions.
If you inspect them, report `read.product_code: true`; also report
`read.existing_solution: true` when they provide a ready-made solution, or
`read.adjacent_attempts: true` when they contain prior trial outputs.
```
- [ ] **Step 3: Verify and commit**
```powershell
uv run pytest tests/examples/test_agent_challenge_harness_v2.py -k base_prompt -q
git add examples/agent_challenges/base-prompt.md tests/examples/test_agent_challenge_harness_v2.py
git commit -m "docs: clarify challenge self-report rules"
```
### Task 6: Final Verification And Documentation
**Files:**
- Modify: `docs/current_roadmap.md`
- Move this plan to `docs/historical/superpowers/plans/`.
- [ ] **Step 1: Run verification**
```powershell
uv run pytest tests/examples/test_agent_challenge_reports.py tests/examples/test_agent_challenge_harness_v2.py tests/examples/test_agent_challenge_skill_bundle.py tests/examples/test_opencode_browser_click_challenge.py tests/examples/test_report_workflow_challenge.py -q
uv run ruff check examples/agent_challenges tests/examples/test_agent_challenge_reports.py tests/examples/test_agent_challenge_harness_v2.py
uv run ruff format --check examples/agent_challenges tests/examples/test_agent_challenge_reports.py tests/examples/test_agent_challenge_harness_v2.py
uv run basedpyright --level error examples/agent_challenges tests/examples/test_agent_challenge_reports.py tests/examples/test_agent_challenge_harness_v2.py
git diff --check
```
- [ ] **Step 2: Smoke CLI help**
```powershell
uv run python examples/agent_challenges/run_trials.py --help
uv run python examples/agent_challenges/save_manual_audit.py --help
```
- [ ] **Step 3: Update roadmap and archive**
Record completion, then move this plan to
`docs/historical/superpowers/plans/2026-06-23-agent-challenge-report-projections.md`.
- [ ] **Step 4: Review boundaries**
Confirm raw result is written once, machine report excludes raw outputs,
Markdown headings are stable, explicit paths are used, audit regenerates both,
V1 remains intact, and no runbook/branching challenge leaked into this slice.
- [ ] **Step 5: Commit completion docs**
```powershell
git add docs/current_roadmap.md docs/superpowers/plans/2026-06-23-agent-challenge-report-projections.md docs/historical/superpowers/plans/2026-06-23-agent-challenge-report-projections.md
git commit -m "docs: record agent challenge report projections"
```
@@ -1,490 +0,0 @@
# Explain Draft Diagnostics Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Extend `wf explain` with draft/workflow validation codes using real enum/constant sources instead of copied strings.
**Architecture:** Keep `wf explain` exact-match and docs-backed. Add enum-backed explain entries for `wf_core.validation.issues.ValidationIssueCode` values, introduce constants for draft/store-only codes, and update tests/docs so agents can explain draft failures without reading source/tests.
**Tech Stack:** Python 3.14, Typer CLI, Pydantic models, pytest, Ruff, basedpyright.
---
## File Structure
- Modify `src/wf_cli/explain/entries.py`: import enum/constants and add cards.
- Modify `src/wf_artifacts/drafts/api.py`: expose draft diagnostic code constants.
- Modify `src/wf_artifacts/draft_workspaces/api.py`: expose workspace diagnostic code constants.
- Modify `tests/wf_cli/test_explain.py`: cover new cards, enum-backed codes, and input-file extraction.
- Modify `docs/wf_cli.md`: expand common diagnostics.
- Modify `skills/wf-cli/SKILL.md` and `skills/wf-workflow/references/troubleshooting.md`: teach `wf explain` for draft codes.
- Modify `docs/current_roadmap.md`: mark completion when done.
### Task 1: Add Constants For Non-Enum Draft Codes
**Files:**
- Modify: `src/wf_artifacts/drafts/api.py`
- Modify: `src/wf_artifacts/draft_workspaces/api.py`
- Test: `tests/wf_cli/test_explain.py`
- [ ] **Step 1: Write the failing import test**
Add this test to `tests/wf_cli/test_explain.py`:
```python
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
```
- [ ] **Step 2: Run the test and verify RED**
Run:
```powershell
uv run pytest tests/wf_cli/test_explain.py::test_explain_registry_uses_exported_draft_codes -q
```
Expected: import failure for the new constants.
- [ ] **Step 3: Add exported constants near producers**
In `src/wf_artifacts/drafts/api.py`, near the type aliases, add:
```python
DRAFT_INVALID_CODE = "draft_invalid"
PATCH_INVALID_CODE = "patch_invalid"
DRAFT_NOT_OBJECT_CODE = "draft_not_object"
UNKNOWN_OUTCOME_CODE = "unknown_outcome"
```
Replace the matching string literals in this file:
```python
code=PATCH_INVALID_CODE
code=DRAFT_NOT_OBJECT_CODE
code=DRAFT_INVALID_CODE
code=UNKNOWN_OUTCOME_CODE
```
In `src/wf_artifacts/draft_workspaces/api.py`, near the type aliases, add:
```python
WORKSPACE_EXISTS_CODE = "workspace_exists"
REVISION_CONFLICT_CODE = "revision_conflict"
```
Replace the matching string literals in this file:
```python
code=WORKSPACE_EXISTS_CODE
code=REVISION_CONFLICT_CODE
```
- [ ] **Step 4: Run the focused test and verify it now reaches registry failure**
Run:
```powershell
uv run pytest tests/wf_cli/test_explain.py::test_explain_registry_uses_exported_draft_codes -q
```
Expected: failure because the registry does not yet contain the new codes.
- [ ] **Step 5: Commit**
```powershell
git add src/wf_artifacts/drafts/api.py src/wf_artifacts/draft_workspaces/api.py tests/wf_cli/test_explain.py
git commit -m "refactor: name draft diagnostic codes"
```
### Task 2: Add Enum-Backed Explain Cards
**Files:**
- Modify: `src/wf_cli/explain/entries.py`
- Modify: `tests/wf_cli/test_explain.py`
- [ ] **Step 1: Write failing tests for workflow validation cards**
Add this test to `tests/wf_cli/test_explain.py`:
```python
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
```
Add this behavior test:
```python
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()
```
- [ ] **Step 2: Run tests and verify RED**
Run:
```powershell
uv run pytest tests/wf_cli/test_explain.py::test_explain_registry_covers_core_validation_codes tests/wf_cli/test_explain.py::test_explain_unknown_edge_destination_mentions_forward_route_repair -q
```
Expected: unknown code / missing registry entries.
- [ ] **Step 3: Import real code sources**
At the top of `src/wf_cli/explain/entries.py`, add:
```python
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,
)
from wf_core.validation.issues import ValidationIssueCode
```
- [ ] **Step 4: Add the new cards**
Append these `ExplainCard` entries to `EXPLAIN_CARDS`:
```python
ExplainCard(
code=ValidationIssueCode.INVALID_SOURCE_PATH.value,
summary="A workflow step reads from a path that is not declared or available.",
why_it_happens=[
"A step input binding points at input/state/context data that the draft schema does not declare.",
"A literal placeholder or guessed path was used in a binding.",
"A wrapper bootstrap included a field that is not present in the actual run input.",
],
how_to_fix=[
"Run `wf schema InputPathBinding` to confirm binding shape.",
"Inspect the draft input and state schemas.",
"Use `wf draft set-input --merge` to repair step input bindings.",
"Patch the draft input_schema/state_schema when the workflow genuinely needs a new path.",
"Run `wf draft validate <workspace_id>` after the edit.",
],
related_docs=[
"docs/wf_cli.md#draft-workspaces",
"docs/workflow_drafts.md",
],
),
ExplainCard(
code=ValidationIssueCode.INVALID_DESTINATION_PATH.value,
summary="A workflow step writes to a state or output path that is not declared.",
why_it_happens=[
"A capability output is bound to a missing state_schema field.",
"A workflow output projection points at a missing output_schema field.",
"A draft patch changed output bindings without changing the matching schema.",
],
how_to_fix=[
"For capability output to state, prefer `wf draft bind --from local.FIELD --to state.FIELD`.",
"For multiple output bindings, use `wf draft set-output --merge` when preserving existing mappings.",
"Read any `repair_hint` returned by `wf draft validate` before writing JSON Patch.",
"Run `wf draft validate <workspace_id>` after the edit.",
],
related_docs=[
"docs/wf_cli.md#draft-workspaces",
"docs/workflow_drafts.md",
],
),
ExplainCard(
code=ValidationIssueCode.UNKNOWN_EDGE_DESTINATION.value,
summary="A route or edge points at a step id that does not exist in the workflow.",
why_it_happens=[
"A draft route was added before the target step was created.",
"A step id was misspelled in a route or edge.",
"A raw plan edge references a node id that is absent from `nodes`.",
],
how_to_fix=[
"In draft authoring, create the target step first, then route to it.",
"Use `wf draft handle <workspace_id> --step FROM --outcome OUTCOME --to TARGET` to repair one route.",
"Use `wf draft branch <workspace_id> --step FROM --route OUTCOME=TARGET` for multiple route edits.",
"For a complete graph authored at once, prefer `wf artifact create-from-plan` and validate the raw plan shape.",
],
related_docs=[
"docs/wf_cli.md#draft-workspaces",
"docs/workflow_drafts.md",
],
),
ExplainCard(
code=ValidationIssueCode.UNDECLARED_EDGE_OUTCOME.value,
summary="A route uses an outcome that the source step does not declare.",
why_it_happens=[
"The route outcome was guessed instead of read from capability metadata.",
"A multi-outcome capability was wired with an incomplete or misspelled outcome map.",
],
how_to_fix=[
"Run `wf cap inspect <capability>` and read the declared outcomes.",
"Use `wf draft handle` or `wf draft branch` with the exact outcome names.",
"Run `wf draft validate <workspace_id>` after route edits.",
],
related_docs=[
"docs/wf_cli.md#draft-workspaces",
"docs/workflow_capabilities.md",
],
),
ExplainCard(
code=ValidationIssueCode.MISSING_OUTCOME_EDGE.value,
summary="A step outcome has no route and the workflow cannot prove where execution goes next.",
why_it_happens=[
"A multi-outcome step was added without complete route coverage.",
"A draft patch replaced a route map and dropped an existing outcome.",
],
how_to_fix=[
"Run `wf cap inspect <capability>` to list declared outcomes.",
"Use `wf draft branch --route OUTCOME=TARGET` for each missing outcome.",
"Route terminal outcomes to `__end__` when the workflow should finish.",
],
related_docs=[
"docs/wf_cli.md#draft-workspaces",
"docs/workflow_drafts.md",
],
),
```
Also append these draft/workspace cards:
```python
ExplainCard(
code=UNKNOWN_OUTCOME_CODE,
summary="A draft route uses an outcome that the source step cannot produce.",
why_it_happens=[
"The route outcome was guessed instead of read from the capability contract.",
"A draft patch preserved an old outcome after the step capability changed.",
],
how_to_fix=[
"Run `wf cap inspect <capability>` and read the declared outcomes.",
"Use `wf draft handle <workspace_id> --step STEP --outcome OUTCOME --to TARGET` with a declared outcome.",
"Use `wf draft branch <workspace_id> --step STEP --route OUTCOME=TARGET` when repairing multiple outcomes.",
"Run `wf draft validate <workspace_id>` after route edits.",
],
related_docs=[
"docs/wf_cli.md#draft-workspaces",
"docs/workflow_drafts.md",
],
),
ExplainCard(
code=DRAFT_INVALID_CODE,
summary="A draft workspace contains an invalid draft shape or invalid workflow structure.",
why_it_happens=[
"The payload mixed draft-workspace shape with raw-plan shape.",
"A JSON Patch produced a draft that does not satisfy the draft model.",
"The draft model is syntactically valid but workflow validation found structural issues.",
],
how_to_fix=[
"Run `wf schema draft` for draft workspace payloads.",
"Run `wf schema raw` for `wf artifact create-from-plan` payloads.",
"Run `wf draft validate <workspace_id>` and follow each diagnostic code.",
"Use `wf explain <code>` for the nested diagnostics before patching again.",
],
related_docs=[
"docs/wf_cli.md#draft-workspaces",
"docs/workflow_drafts.md",
],
),
ExplainCard(
code=PATCH_INVALID_CODE,
summary="A draft patch is not a valid RFC 6902 JSON Patch or cannot be applied.",
why_it_happens=[
"The patch file used raw draft JSON instead of a JSON Patch operation list.",
"A patch path points at a missing parent object.",
"A patch operation is malformed or unsupported by the patch library.",
],
how_to_fix=[
"Use focused commands such as `wf draft set-input`, `wf draft set-output`, `wf draft bind`, `wf draft handle`, and `wf draft branch` when possible.",
"If using `wf draft patch`, make the file a JSON array of RFC 6902 operations.",
"Run `wf schema draft` to inspect the draft shape before choosing patch paths.",
"Retry with the current workspace revision.",
],
related_docs=[
"docs/wf_cli.md#draft-workspaces",
"docs/workflow_drafts.md",
],
),
ExplainCard(
code=REVISION_CONFLICT_CODE,
summary="A draft command used a stale workspace revision.",
why_it_happens=[
"Another edit advanced the draft workspace revision.",
"The command was retried with an old `--revision` value.",
"An agent copied a prior command transcript without fetching the current workspace.",
],
how_to_fix=[
"Run `wf draft inspect <workspace_id>` to get the current revision.",
"Repeat the edit with the current `--revision` value.",
"Do not skip revision checks; they prevent overwriting another edit.",
],
related_docs=[
"docs/wf_cli.md#draft-workspaces",
"docs/workflow_drafts.md",
],
),
```
- [ ] **Step 5: Run explain tests**
Run:
```powershell
uv run pytest tests/wf_cli/test_explain.py -q
```
Expected: PASS.
- [ ] **Step 6: Commit**
```powershell
git add src/wf_cli/explain/entries.py tests/wf_cli/test_explain.py
git commit -m "feat: explain draft validation codes"
```
### Task 3: Update User-Facing Docs And Skills
**Files:**
- Modify: `docs/wf_cli.md`
- Modify: `skills/wf-cli/SKILL.md`
- Modify: `skills/wf-workflow/references/troubleshooting.md`
- Modify: `docs/current_roadmap.md`
- [ ] **Step 1: Update docs**
In `docs/wf_cli.md`, under `## Explain`, add a short list of draft examples:
```markdown
Draft authoring diagnostics commonly include:
- `invalid_source_path`
- `invalid_destination_path`
- `unknown_edge_destination`
- `unknown_outcome`
- `patch_invalid`
- `revision_conflict`
```
In `skills/wf-cli/SKILL.md`, add:
```markdown
For draft validation errors, run `wf explain <code>`. If routes point to a
missing step, create the target step first or repair routes with
`wf draft handle` / `wf draft branch`.
```
In `skills/wf-workflow/references/troubleshooting.md`, add:
```markdown
`unknown_edge_destination`: a route points to a missing step. Add the target
step or repair the route; do not guess `draft step add` or `draft export`.
```
- [ ] **Step 2: Update roadmap**
Add a completed bullet under Priority 1:
```markdown
- Completed: `wf explain` now covers draft/workflow validation codes such as
`unknown_edge_destination`, `invalid_source_path`, and `patch_invalid`.
```
- [ ] **Step 3: Verify docs and skills**
Run:
```powershell
uv run pytest tests/docs tests/wf_cli/test_explain.py -q
uv run ruff check src/wf_cli/explain/entries.py tests/wf_cli/test_explain.py
uv run basedpyright --level error src/wf_cli/explain/entries.py tests/wf_cli/test_explain.py
```
Expected: all pass.
- [ ] **Step 4: Commit**
```powershell
git add docs/wf_cli.md skills/wf-cli/SKILL.md skills/wf-workflow/references/troubleshooting.md docs/current_roadmap.md
git commit -m "docs: teach draft explain codes"
```
### Task 4: Final Verification
**Files:**
- Move: `docs/superpowers/plans/2026-06-28-explain-draft-diagnostics.md`
- Modify: `docs/current_roadmap.md`
- [ ] **Step 1: Smoke the CLI**
Run:
```powershell
uv run wf explain unknown_edge_destination --format compact
uv run wf explain invalid_destination_path --format markdown
uv run wf explain --list --format compact
```
Expected: each command exits 0 and prints useful text.
- [ ] **Step 2: Archive the plan**
Move this plan to:
```text
docs/historical/superpowers/plans/2026-06-28-explain-draft-diagnostics.md
```
- [ ] **Step 3: Run final checks**
Run:
```powershell
uv run pytest tests/wf_cli/test_explain.py tests/docs -q
uv run ruff check src/wf_cli/explain/entries.py tests/wf_cli/test_explain.py
uv run ruff format --check src/wf_cli/explain/entries.py tests/wf_cli/test_explain.py
uv run basedpyright --level error src/wf_cli/explain/entries.py tests/wf_cli/test_explain.py
```
Expected: all pass.
- [ ] **Step 4: Commit**
```powershell
git add docs/current_roadmap.md docs/historical/superpowers/plans/2026-06-28-explain-draft-diagnostics.md
git commit -m "docs: archive draft explain plan"
```
## Self-Review
- Spec coverage: all acceptance criteria from `2026-06-28-explain-draft-diagnostics.md` map to Tasks 1-4.
- Placeholder scan: no placeholders remain.
- Type consistency: enum-backed codes come from `ValidationIssueCode`; draft-only codes come from exported constants.