docs: make lda report plan authoring-first
This commit is contained in:
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
**Goal:** Add a deterministic `examples/lda_report_workflow/` case study that exercises document reading, report synthesis, a typed human approval interrupt, issue creation, resume, trace, and final output.
|
**Goal:** Add a deterministic `examples/lda_report_workflow/` case study that exercises document reading, report synthesis, a typed human approval interrupt, issue creation, resume, trace, and final output.
|
||||||
|
|
||||||
**Architecture:** Implement three trusted Python sources in one example package: `local.lda_docs`, `local.lda_report`, and `local.issue_board`. Ship a raw workflow plan that uses the new self-describing interrupt contract, plus tests that run artifact, deployment, interrupt inspection, resume, issue creation, and final output through the product API.
|
**Architecture:** Implement three trusted Python sources in one example package: `local.lda_docs`, `local.lda_report`, and `local.issue_board`. Author the graph with `wf_authoring.WorkflowBuilder`, generate a committed raw workflow plan from the compiled `Workflow`, and test artifact, deployment, interrupt inspection, resume, issue creation, and final output through the product API.
|
||||||
|
|
||||||
**Tech Stack:** Python 3.14, Pydantic models, static Python workflow sources, raw workflow plans, `wf_config`, `wf_server`, pytest.
|
**Tech Stack:** Python 3.14, Pydantic models, `wf_authoring.WorkflowBuilder`, static Python workflow sources, generated raw workflow plans, `wf_config`, `wf_server`, pytest.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -36,9 +36,10 @@ examples/lda_report_workflow/
|
|||||||
document_source.py
|
document_source.py
|
||||||
report_source.py
|
report_source.py
|
||||||
issue_board_source.py
|
issue_board_source.py
|
||||||
|
build_workflow.py
|
||||||
run-input.json
|
run-input.json
|
||||||
wf.config.json
|
wf.config.json
|
||||||
workflow.plan.json
|
workflow.plan.json # generated by build_workflow.py and committed
|
||||||
```
|
```
|
||||||
|
|
||||||
Create tests:
|
Create tests:
|
||||||
@@ -98,7 +99,8 @@ The interrupt:
|
|||||||
- request payload contains rendered report markdown and proposed issues
|
- request payload contains rendered report markdown and proposed issues
|
||||||
- resume payload contains `approved`, `selected_issue_ids`, and optional
|
- resume payload contains `approved`, `selected_issue_ids`, and optional
|
||||||
`comment`
|
`comment`
|
||||||
- request/resume schemas are explicit JSON Schema objects in the raw plan
|
- request/resume schemas are explicit JSON Schema objects authored in
|
||||||
|
`build_workflow.py` and generated into the raw plan
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -981,11 +983,12 @@ git commit -m "feat: add local issue board source example"
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Task 5: Add Config, Run Input, And Raw Workflow Plan
|
### Task 5: Add Config, Run Input, And Workflow Builder
|
||||||
|
|
||||||
**Files:**
|
**Files:**
|
||||||
- Create: `examples/lda_report_workflow/wf.config.json`
|
- Create: `examples/lda_report_workflow/wf.config.json`
|
||||||
- Create: `examples/lda_report_workflow/run-input.json`
|
- Create: `examples/lda_report_workflow/run-input.json`
|
||||||
|
- Create: `examples/lda_report_workflow/build_workflow.py`
|
||||||
- Create: `examples/lda_report_workflow/workflow.plan.json`
|
- Create: `examples/lda_report_workflow/workflow.plan.json`
|
||||||
- Modify: `tests/examples/test_lda_report_workflow_example.py`
|
- Modify: `tests/examples/test_lda_report_workflow_example.py`
|
||||||
|
|
||||||
@@ -1052,12 +1055,17 @@ Create `examples/lda_report_workflow/run-input.json`:
|
|||||||
|
|
||||||
- [ ] **Step 3: Add config loading test**
|
- [ ] **Step 3: Add config loading test**
|
||||||
|
|
||||||
Append to `tests/examples/test_lda_report_workflow_example.py`:
|
Add these imports to the top import block in
|
||||||
|
`tests/examples/test_lda_report_workflow_example.py`:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from wf_config import load_workflow_config
|
from wf_config import load_workflow_config
|
||||||
from wf_server.config import build_workflow_server_from_workflow_config
|
from wf_server.config import build_workflow_server_from_workflow_config
|
||||||
|
```
|
||||||
|
|
||||||
|
Append this test:
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_lda_report_workflow_config_loads_sources(tmp_path: Path) -> None:
|
async def test_lda_report_workflow_config_loads_sources(tmp_path: Path) -> None:
|
||||||
@@ -1082,203 +1090,276 @@ uv run pytest tests/examples/test_lda_report_workflow_example.py::test_lda_repor
|
|||||||
|
|
||||||
Expected: pass.
|
Expected: pass.
|
||||||
|
|
||||||
- [ ] **Step 5: Create raw workflow plan**
|
- [ ] **Step 5: Create workflow builder**
|
||||||
|
|
||||||
Create `examples/lda_report_workflow/workflow.plan.json` with this content:
|
Create `examples/lda_report_workflow/build_workflow.py`:
|
||||||
|
|
||||||
```json
|
```python
|
||||||
{
|
from __future__ import annotations
|
||||||
"name": "lda_report_case_study",
|
|
||||||
"input_schema": {
|
import json
|
||||||
"type": "object",
|
from pathlib import Path
|
||||||
"properties": {
|
from typing import Any
|
||||||
"selected_documents": {
|
|
||||||
"type": "array",
|
from wf_api.models import RawWorkflowPlan
|
||||||
"items": {"type": "string"}
|
from wf_authoring import WorkflowBuilder
|
||||||
},
|
from wf_core import Workflow
|
||||||
"board_path": {"type": "string"}
|
|
||||||
},
|
HERE = Path(__file__).resolve().parent
|
||||||
"required": ["selected_documents", "board_path"]
|
|
||||||
},
|
WORKFLOW_OUTPUT = [
|
||||||
"state_schema": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"documents": {"type": "array"},
|
|
||||||
"analysis": {"type": "array"},
|
|
||||||
"report": {"type": "object"},
|
|
||||||
"report_markdown": {"type": "string"},
|
|
||||||
"proposed_issues": {"type": "array"},
|
|
||||||
"selected_issue_ids": {"type": "array"},
|
|
||||||
"approval_comment": {"type": "string"},
|
|
||||||
"approved": {"type": "boolean"},
|
|
||||||
"created_issues": {"type": "array"},
|
|
||||||
"final_markdown": {"type": "string"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"output_schema": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"approved": {"type": "boolean"},
|
|
||||||
"markdown": {"type": "string"},
|
|
||||||
"created_issues": {"type": "array"},
|
|
||||||
"selected_issue_ids": {"type": "array"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"output": [
|
|
||||||
{"path": "state.approved", "target": "approved"},
|
{"path": "state.approved", "target": "approved"},
|
||||||
{"path": "state.final_markdown", "target": "markdown"},
|
{"path": "state.final_markdown", "target": "markdown"},
|
||||||
{"path": "state.created_issues", "target": "created_issues"},
|
{"path": "state.created_issues", "target": "created_issues"},
|
||||||
{"path": "state.selected_issue_ids", "target": "selected_issue_ids"}
|
{"path": "state.selected_issue_ids", "target": "selected_issue_ids"},
|
||||||
],
|
]
|
||||||
"outcomes": ["completed", "cancelled"],
|
|
||||||
"start": "read_docs",
|
|
||||||
"nodes": [
|
def build_workflow() -> Workflow:
|
||||||
{
|
"""Build the demo workflow with the public authoring API.
|
||||||
"id": "read_docs",
|
|
||||||
"type": "node",
|
`WorkflowBuilder` does not yet expose a workflow-output setter, so this
|
||||||
"node": "local.lda_docs.read_documents",
|
module adds the final output projection in `_with_workflow_output()` after
|
||||||
"input": [
|
compiling the graph. Keep that seam small and validated.
|
||||||
{"path": "input.selected_documents", "target": "names"}
|
"""
|
||||||
],
|
builder = WorkflowBuilder(
|
||||||
"output": [
|
name="lda_report_case_study",
|
||||||
{"source": "documents", "target": "state.documents"}
|
input_schema={
|
||||||
]
|
"type": "object",
|
||||||
},
|
"properties": {
|
||||||
{
|
"selected_documents": {
|
||||||
"id": "analyze",
|
"type": "array",
|
||||||
"type": "node",
|
"items": {"type": "string"},
|
||||||
"node": "local.lda_report.analyze_documents",
|
},
|
||||||
"input": [
|
"board_path": {"type": "string"},
|
||||||
{"path": "state.documents", "target": "documents"}
|
},
|
||||||
],
|
"required": ["selected_documents", "board_path"],
|
||||||
"output": [
|
|
||||||
{"source": "analysis", "target": "state.analysis"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "build_report",
|
|
||||||
"type": "node",
|
|
||||||
"node": "local.lda_report.build_report",
|
|
||||||
"input": [
|
|
||||||
{"path": "state.analysis", "target": "analysis"}
|
|
||||||
],
|
|
||||||
"output": [
|
|
||||||
{"source": "report", "target": "state.report"},
|
|
||||||
{"source": "markdown", "target": "state.report_markdown"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "draft_issues",
|
|
||||||
"type": "node",
|
|
||||||
"node": "local.lda_report.create_issue_drafts",
|
|
||||||
"input": [
|
|
||||||
{"path": "state.report", "target": "report"}
|
|
||||||
],
|
|
||||||
"output": [
|
|
||||||
{"source": "issues", "target": "state.proposed_issues"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "review_issues",
|
|
||||||
"type": "interrupt",
|
|
||||||
"kind": "issue_review",
|
|
||||||
"request": [
|
|
||||||
{"path": "state.report_markdown", "target": "report_markdown"},
|
|
||||||
{"path": "state.proposed_issues", "target": "proposed_issues"}
|
|
||||||
],
|
|
||||||
"resume": [
|
|
||||||
{"source": "approved", "target": "state.approved"},
|
|
||||||
{"source": "selected_issue_ids", "target": "state.selected_issue_ids"},
|
|
||||||
{"source": "comment", "target": "state.approval_comment"}
|
|
||||||
],
|
|
||||||
"outcomes": ["submitted", "cancelled"],
|
|
||||||
"request_schema": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"report_markdown": {"type": "string"},
|
|
||||||
"proposed_issues": {"type": "array"}
|
|
||||||
},
|
},
|
||||||
"required": ["report_markdown", "proposed_issues"],
|
state_schema={
|
||||||
"additionalProperties": false
|
"type": "object",
|
||||||
},
|
"properties": {
|
||||||
"resume_schema": {
|
"documents": {"type": "array"},
|
||||||
"type": "object",
|
"analysis": {"type": "array"},
|
||||||
"properties": {
|
"report": {"type": "object"},
|
||||||
"approved": {"type": "boolean"},
|
"report_markdown": {"type": "string"},
|
||||||
"selected_issue_ids": {
|
"proposed_issues": {"type": "array"},
|
||||||
"type": "array",
|
"selected_issue_ids": {"type": "array"},
|
||||||
"items": {"type": "string"}
|
"approval_comment": {"type": "string"},
|
||||||
},
|
"approved": {"type": "boolean"},
|
||||||
"comment": {"type": "string"}
|
"created_issues": {"type": "array"},
|
||||||
|
"final_markdown": {"type": "string"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"required": ["approved", "selected_issue_ids"],
|
output_schema={
|
||||||
"additionalProperties": false
|
"type": "object",
|
||||||
}
|
"properties": {
|
||||||
},
|
"approved": {"type": "boolean"},
|
||||||
{
|
"markdown": {"type": "string"},
|
||||||
"id": "create_issues",
|
"created_issues": {"type": "array"},
|
||||||
"type": "node",
|
"selected_issue_ids": {"type": "array"},
|
||||||
"node": "local.issue_board.create_issues",
|
},
|
||||||
"input": [
|
},
|
||||||
{"path": "state.proposed_issues", "target": "issues"},
|
outcomes=["completed", "cancelled"],
|
||||||
{"path": "state.selected_issue_ids", "target": "selected_issue_ids"},
|
)
|
||||||
{"path": "input.board_path", "target": "board_path"}
|
|
||||||
],
|
read_docs = builder.use_ref(
|
||||||
"output": [
|
"local.lda_docs.read_documents",
|
||||||
{"source": "created_issues", "target": "state.created_issues"}
|
id="read_docs",
|
||||||
]
|
input=[{"path": "input.selected_documents", "target": "names"}],
|
||||||
},
|
output=[{"source": "documents", "target": "state.documents"}],
|
||||||
{
|
)
|
||||||
"id": "finalise",
|
analyze = builder.use_ref(
|
||||||
"type": "node",
|
"local.lda_report.analyze_documents",
|
||||||
"node": "local.lda_report.finalise_report",
|
id="analyze",
|
||||||
"input": [
|
input=[{"path": "state.documents", "target": "documents"}],
|
||||||
{"path": "state.report", "target": "report"},
|
output=[{"source": "analysis", "target": "state.analysis"}],
|
||||||
{"path": "state.created_issues", "target": "created_issues"},
|
)
|
||||||
{"path": "state.approved", "target": "approved"},
|
build_report = builder.use_ref(
|
||||||
{"path": "state.selected_issue_ids", "target": "selected_issue_ids"},
|
"local.lda_report.build_report",
|
||||||
{"path": "state.approval_comment", "target": "comment"}
|
id="build_report",
|
||||||
],
|
input=[{"path": "state.analysis", "target": "analysis"}],
|
||||||
"output": [
|
output=[
|
||||||
{"source": "markdown", "target": "state.final_markdown"}
|
{"source": "report", "target": "state.report"},
|
||||||
]
|
{"source": "markdown", "target": "state.report_markdown"},
|
||||||
},
|
],
|
||||||
{
|
)
|
||||||
"id": "revision_requested",
|
draft_issues = builder.use_ref(
|
||||||
"type": "node",
|
"local.lda_report.create_issue_drafts",
|
||||||
"node": "local.lda_report.record_revision_request",
|
id="draft_issues",
|
||||||
"input": [
|
input=[{"path": "state.report", "target": "report"}],
|
||||||
{"path": "state.approval_comment", "target": "comment"}
|
output=[{"source": "issues", "target": "state.proposed_issues"}],
|
||||||
],
|
)
|
||||||
"output": [
|
review_issues = builder.interrupt(
|
||||||
{"source": "approved", "target": "state.approved"},
|
id="review_issues",
|
||||||
{"source": "markdown", "target": "state.final_markdown"},
|
kind="issue_review",
|
||||||
{"source": "created_issues", "target": "state.created_issues"},
|
request=[
|
||||||
{"source": "selected_issue_ids", "target": "state.selected_issue_ids"}
|
{"path": "state.report_markdown", "target": "report_markdown"},
|
||||||
]
|
{"path": "state.proposed_issues", "target": "proposed_issues"},
|
||||||
},
|
],
|
||||||
{"id": "end_completed", "type": "end", "outcome": "completed"},
|
resume=[
|
||||||
{"id": "end_cancelled", "type": "end", "outcome": "cancelled"}
|
{"source": "approved", "target": "state.approved"},
|
||||||
],
|
{"source": "selected_issue_ids", "target": "state.selected_issue_ids"},
|
||||||
"edges": [
|
{"source": "comment", "target": "state.approval_comment"},
|
||||||
{"from": "read_docs", "outcome": "ok", "to": "analyze"},
|
],
|
||||||
{"from": "analyze", "outcome": "ok", "to": "build_report"},
|
outcomes=["submitted", "cancelled"],
|
||||||
{"from": "build_report", "outcome": "ok", "to": "draft_issues"},
|
request_schema={
|
||||||
{"from": "draft_issues", "outcome": "ok", "to": "review_issues"},
|
"type": "object",
|
||||||
{"from": "review_issues", "outcome": "submitted", "to": "create_issues"},
|
"properties": {
|
||||||
{"from": "review_issues", "outcome": "cancelled", "to": "revision_requested"},
|
"report_markdown": {"type": "string"},
|
||||||
{"from": "create_issues", "outcome": "ok", "to": "finalise"},
|
"proposed_issues": {"type": "array"},
|
||||||
{"from": "finalise", "outcome": "ok", "to": "end_completed"},
|
},
|
||||||
{"from": "revision_requested", "outcome": "ok", "to": "end_cancelled"}
|
"required": ["report_markdown", "proposed_issues"],
|
||||||
]
|
"additionalProperties": False,
|
||||||
}
|
},
|
||||||
|
resume_schema={
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"approved": {"type": "boolean"},
|
||||||
|
"selected_issue_ids": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"type": "string"},
|
||||||
|
},
|
||||||
|
"comment": {"type": "string"},
|
||||||
|
},
|
||||||
|
"required": ["approved", "selected_issue_ids"],
|
||||||
|
"additionalProperties": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
create_issues = builder.use_ref(
|
||||||
|
"local.issue_board.create_issues",
|
||||||
|
id="create_issues",
|
||||||
|
input=[
|
||||||
|
{"path": "state.proposed_issues", "target": "issues"},
|
||||||
|
{"path": "state.selected_issue_ids", "target": "selected_issue_ids"},
|
||||||
|
{"path": "input.board_path", "target": "board_path"},
|
||||||
|
],
|
||||||
|
output=[{"source": "created_issues", "target": "state.created_issues"}],
|
||||||
|
)
|
||||||
|
finalise = builder.use_ref(
|
||||||
|
"local.lda_report.finalise_report",
|
||||||
|
id="finalise",
|
||||||
|
input=[
|
||||||
|
{"path": "state.report", "target": "report"},
|
||||||
|
{"path": "state.created_issues", "target": "created_issues"},
|
||||||
|
{"path": "state.approved", "target": "approved"},
|
||||||
|
{"path": "state.selected_issue_ids", "target": "selected_issue_ids"},
|
||||||
|
{"path": "state.approval_comment", "target": "comment"},
|
||||||
|
],
|
||||||
|
output=[{"source": "markdown", "target": "state.final_markdown"}],
|
||||||
|
)
|
||||||
|
revision_requested = builder.use_ref(
|
||||||
|
"local.lda_report.record_revision_request",
|
||||||
|
id="revision_requested",
|
||||||
|
input=[{"path": "state.approval_comment", "target": "comment"}],
|
||||||
|
output=[
|
||||||
|
{"source": "approved", "target": "state.approved"},
|
||||||
|
{"source": "markdown", "target": "state.final_markdown"},
|
||||||
|
{"source": "created_issues", "target": "state.created_issues"},
|
||||||
|
{"source": "selected_issue_ids", "target": "state.selected_issue_ids"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
end_completed = builder.end("completed", id="end_completed")
|
||||||
|
end_cancelled = builder.end("cancelled", id="end_cancelled")
|
||||||
|
|
||||||
|
builder.set_entry_point(read_docs)
|
||||||
|
builder.connect(read_docs, "ok", analyze)
|
||||||
|
builder.connect(analyze, "ok", build_report)
|
||||||
|
builder.connect(build_report, "ok", draft_issues)
|
||||||
|
builder.branch(
|
||||||
|
review_issues,
|
||||||
|
{
|
||||||
|
"submitted": create_issues,
|
||||||
|
"cancelled": revision_requested,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
builder.connect(create_issues, "ok", finalise)
|
||||||
|
builder.connect(finalise, "ok", end_completed)
|
||||||
|
builder.connect(revision_requested, "ok", end_cancelled)
|
||||||
|
return _with_workflow_output(builder.compile())
|
||||||
|
|
||||||
|
|
||||||
|
def _with_workflow_output(workflow: Workflow) -> Workflow:
|
||||||
|
payload = workflow.model_dump(mode="json", by_alias=True)
|
||||||
|
payload["output"] = WORKFLOW_OUTPUT
|
||||||
|
return Workflow.model_validate(payload)
|
||||||
|
|
||||||
|
|
||||||
|
def workflow_plan_payload() -> dict[str, Any]:
|
||||||
|
payload = build_workflow().model_dump(mode="json", by_alias=True)
|
||||||
|
payload.pop("node_defs", None)
|
||||||
|
RawWorkflowPlan.model_validate(payload)
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def write_plan(path: Path = HERE / "workflow.plan.json") -> None:
|
||||||
|
payload = workflow_plan_payload()
|
||||||
|
path.write_text(
|
||||||
|
json.dumps(payload, indent=2, sort_keys=True) + "\n",
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
write_plan()
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Step 6: Commit config and plan**
|
- [ ] **Step 6: Generate raw workflow plan**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
git add examples/lda_report_workflow/wf.config.json examples/lda_report_workflow/run-input.json examples/lda_report_workflow/workflow.plan.json tests/examples/test_lda_report_workflow_example.py
|
uv run python examples/lda_report_workflow/build_workflow.py
|
||||||
git commit -m "feat: add lda report workflow plan"
|
```
|
||||||
|
|
||||||
|
Expected: `examples/lda_report_workflow/workflow.plan.json` is written.
|
||||||
|
|
||||||
|
- [ ] **Step 7: Add builder/generator regression test**
|
||||||
|
|
||||||
|
Add these imports to the top import block:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import json
|
||||||
|
|
||||||
|
from examples.lda_report_workflow.build_workflow import (
|
||||||
|
build_workflow,
|
||||||
|
workflow_plan_payload,
|
||||||
|
)
|
||||||
|
from wf_api.models import RawWorkflowPlan
|
||||||
|
```
|
||||||
|
|
||||||
|
Append this test:
|
||||||
|
|
||||||
|
```python
|
||||||
|
|
||||||
|
def test_lda_report_workflow_builder_generates_committed_raw_plan() -> None:
|
||||||
|
workflow = build_workflow()
|
||||||
|
payload = workflow_plan_payload()
|
||||||
|
committed = json.loads(
|
||||||
|
(EXAMPLE_DIR / "workflow.plan.json").read_text(encoding="utf-8")
|
||||||
|
)
|
||||||
|
validated = RawWorkflowPlan.model_validate(payload)
|
||||||
|
|
||||||
|
assert workflow.name == "lda_report_case_study"
|
||||||
|
assert validated.name == "lda_report_case_study"
|
||||||
|
assert any(node.id == "review_issues" for node in validated.nodes)
|
||||||
|
assert payload == committed
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 8: Run builder and config tests**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
uv run pytest tests/examples/test_lda_report_workflow_example.py::test_lda_report_workflow_config_loads_sources tests/examples/test_lda_report_workflow_example.py::test_lda_report_workflow_builder_generates_committed_raw_plan -q -n0
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: pass.
|
||||||
|
|
||||||
|
- [ ] **Step 9: Commit config, builder, and plan**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add examples/lda_report_workflow/wf.config.json examples/lda_report_workflow/run-input.json examples/lda_report_workflow/build_workflow.py examples/lda_report_workflow/workflow.plan.json tests/examples/test_lda_report_workflow_example.py
|
||||||
|
git commit -m "feat: add lda report workflow builder"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -1290,12 +1371,10 @@ git commit -m "feat: add lda report workflow plan"
|
|||||||
|
|
||||||
- [ ] **Step 1: Add full lifecycle test**
|
- [ ] **Step 1: Add full lifecycle test**
|
||||||
|
|
||||||
Append to `tests/examples/test_lda_report_workflow_example.py`:
|
Append to `tests/examples/test_lda_report_workflow_example.py`. Do not add a
|
||||||
|
second `import json`; Task 5 already added it to the top import block.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_lda_report_workflow_artifact_interrupt_resume_path(tmp_path: Path) -> None:
|
async def test_lda_report_workflow_artifact_interrupt_resume_path(tmp_path: Path) -> None:
|
||||||
config = load_workflow_config(EXAMPLE_DIR / "wf.config.json")
|
config = load_workflow_config(EXAMPLE_DIR / "wf.config.json")
|
||||||
@@ -1486,6 +1565,15 @@ It does not call Google Drive, email, GitHub, or an LLM.
|
|||||||
proposed issue drafts, and finalises the report.
|
proposed issue drafts, and finalises the report.
|
||||||
- `local.issue_board`: writes selected issues to a local JSON file.
|
- `local.issue_board`: writes selected issues to a local JSON file.
|
||||||
|
|
||||||
|
## Workflow Definition
|
||||||
|
|
||||||
|
`workflow.plan.json` is generated from `build_workflow.py`. After changing the
|
||||||
|
graph, regenerate and review the raw plan:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
uv run python examples/lda_report_workflow/build_workflow.py
|
||||||
|
```
|
||||||
|
|
||||||
## Product Path
|
## Product Path
|
||||||
|
|
||||||
From the repository root:
|
From the repository root:
|
||||||
@@ -1579,14 +1667,17 @@ If either `docs/add/...` file was not changed, omit it from `git add`.
|
|||||||
Run:
|
Run:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
|
uv run python examples/lda_report_workflow/build_workflow.py
|
||||||
|
git diff --exit-code examples/lda_report_workflow/workflow.plan.json
|
||||||
uv run pytest tests/examples/test_lda_report_workflow_example.py tests/wf_sources_python/test_loader.py -q -n0
|
uv run pytest tests/examples/test_lda_report_workflow_example.py tests/wf_sources_python/test_loader.py -q -n0
|
||||||
uv run ruff check examples/lda_report_workflow tests/examples/test_lda_report_workflow_example.py
|
uv run ruff check examples/lda_report_workflow tests/examples/test_lda_report_workflow_example.py
|
||||||
uv run ruff format --check examples/lda_report_workflow tests/examples/test_lda_report_workflow_example.py
|
uv run ruff format --check examples/lda_report_workflow tests/examples/test_lda_report_workflow_example.py
|
||||||
uv run basedpyright --level error examples/lda_report_workflow tests/examples/test_lda_report_workflow_example.py
|
uv run basedpyright --level error examples/lda_report_workflow tests/examples/test_lda_report_workflow_example.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected: all pass. If `basedpyright` reports import-package issues for the
|
Expected: generation exits 0, `git diff --exit-code` reports no generated-plan
|
||||||
example package, add `examples/lda_report_workflow/__init__.py` and rerun.
|
diff, and all checks pass. If `basedpyright` reports import-package issues for
|
||||||
|
the example package, add `examples/lda_report_workflow/__init__.py` and rerun.
|
||||||
|
|
||||||
- [ ] **Step 2: Smoke the CLI path**
|
- [ ] **Step 2: Smoke the CLI path**
|
||||||
|
|
||||||
@@ -1638,7 +1729,7 @@ Spec coverage:
|
|||||||
|
|
||||||
- deterministic documents: Task 1;
|
- deterministic documents: Task 1;
|
||||||
- first-party document/report/issue-board sources: Tasks 2-4;
|
- first-party document/report/issue-board sources: Tasks 2-4;
|
||||||
- raw plan and config: Task 5;
|
- authoring builder, generated raw plan, and config: Task 5;
|
||||||
- typed issue-review interrupt and resume: Task 6;
|
- typed issue-review interrupt and resume: Task 6;
|
||||||
- product runbook and roadmap: Task 7;
|
- product runbook and roadmap: Task 7;
|
||||||
- final verification/archive: Task 8.
|
- final verification/archive: Task 8.
|
||||||
|
|||||||
Reference in New Issue
Block a user