docs: archive completed implementation plans
This commit is contained in:
+30
-30
@@ -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
|
||||
|
||||
+23
-23
@@ -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
|
||||
+1
-1
@@ -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.
|
||||
Reference in New Issue
Block a user