mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
Add DOT docs test suite and fix invalid DOT in docs examples
Extract all 29 full digraph workflows from docs into test/docs/ with an extraction script, assemble 7 snippet DOTs from reference pages, and add a runner script for validate/dry-run/haiku/full phases. Docs fixes: - definition-of-done: replace multi-word condition values with underscored equivalents (parser doesn't support spaces), make safe-default edges unconditional for fallback coverage - semantic-port: make fallback edges unconditional on fetch/analyze nodes so validator doesn't reject all-conditional-edge nodes All 36 DOTs pass `arc validate`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ae3a9e7505
commit
2cce052f9f
47 changed files with 2792 additions and 15 deletions
|
|
@ -149,7 +149,7 @@ Respond with JSON (not by writing out a file):
|
|||
\"remaining_implementable\": M
|
||||
}
|
||||
|
||||
If remaining_implementable > 0, set preferred_next_label to \"More fixes needed\".
|
||||
If remaining_implementable > 0, set preferred_next_label to \"more_fixes_needed\".
|
||||
Otherwise set preferred_next_label to \"Re-audit\"."
|
||||
]
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ Respond with JSON (not by writing out a file):
|
|||
}
|
||||
|
||||
If remaining_total == 0 (ignoring DEFERRED items), set preferred_next_label to \"Complete\".
|
||||
Otherwise set preferred_next_label to \"More work needed\"."
|
||||
Otherwise set preferred_next_label to \"more_work_needed\"."
|
||||
]
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
|
|
@ -238,17 +238,17 @@ Otherwise set preferred_next_label to \"More work needed\"."
|
|||
|
||||
/* Build check outcomes */
|
||||
build_check -> final_audit [label="Build OK", condition="outcome=success"]
|
||||
build_check -> build_fix [label="Build failed", condition="outcome=fail"]
|
||||
build_check -> build_fix [label="Build failed"]
|
||||
|
||||
/* Build fix loops back to build check */
|
||||
build_fix -> build_check
|
||||
|
||||
/* Fix batch can loop for more fixes */
|
||||
fix_batch -> fix_batch [label="More fixes needed", condition="preferred_label=More fixes needed", loop_restart=true]
|
||||
fix_batch -> fix_batch [label="More fixes needed", condition="preferred_label=more_fixes_needed", loop_restart=true]
|
||||
|
||||
/* Final audit outcomes */
|
||||
final_audit -> review_gate [label="Complete", condition="preferred_label=Complete"]
|
||||
final_audit -> triage [label="More work needed", condition="preferred_label=More work needed"]
|
||||
final_audit -> triage [label="More work needed"]
|
||||
|
||||
/* Human review gate */
|
||||
review_gate -> exit [label="A) Accept"]
|
||||
|
|
@ -701,9 +701,9 @@ Respond with JSON (not by writing out a file):
|
|||
\"remaining_implementable\": M
|
||||
}
|
||||
|
||||
If issues_found contains any critical items, set preferred_next_label to \"More fixes needed\".
|
||||
If remaining_implementable > 0 and no critical issues, set preferred_next_label to \"More fixes needed\".
|
||||
Otherwise set preferred_next_label to \"Ready for build\"."
|
||||
If issues_found contains any critical items, set preferred_next_label to \"more_fixes_needed\".
|
||||
If remaining_implementable > 0 and no critical issues, set preferred_next_label to \"more_fixes_needed\".
|
||||
Otherwise set preferred_next_label to \"ready_for_build\"."
|
||||
]
|
||||
|
||||
/*========================================================================
|
||||
|
|
@ -810,7 +810,7 @@ Respond with JSON (not by writing out a file):
|
|||
}
|
||||
|
||||
If remaining_total == 0 (ignoring DEFERRED items), set preferred_next_label to \"Complete\".
|
||||
Otherwise set preferred_next_label to \"More work needed\"."
|
||||
Otherwise set preferred_next_label to \"more_work_needed\"."
|
||||
]
|
||||
|
||||
/*========================================================================
|
||||
|
|
@ -857,12 +857,13 @@ Otherwise set preferred_next_label to \"More work needed\"."
|
|||
review_fix_opus -> review_codex
|
||||
|
||||
/* Implementation loop */
|
||||
review_codex -> fix_codex [label="More fixes needed", condition="preferred_label=More fixes needed", loop_restart=true]
|
||||
review_codex -> build_check [label="Ready for build", condition="preferred_label=Ready for build"]
|
||||
review_codex -> fix_codex [label="More fixes needed", condition="preferred_label=more_fixes_needed", loop_restart=true]
|
||||
review_codex -> build_check [label="Ready for build", condition="preferred_label=ready_for_build"]
|
||||
review_codex -> fix_codex [label="Fallback"]
|
||||
|
||||
/* Phase 6: Build */
|
||||
build_check -> final_audit_opus [label="Build OK", condition="outcome=success"]
|
||||
build_check -> build_fix [label="Build failed", condition="outcome=fail"]
|
||||
build_check -> build_fix [label="Build failed"]
|
||||
build_fix -> build_check
|
||||
|
||||
/* Phase 7: Dual final audit (sequential — Opus then GPT then consensus) */
|
||||
|
|
@ -871,7 +872,7 @@ Otherwise set preferred_next_label to \"More work needed\"."
|
|||
|
||||
/* Final decision */
|
||||
final_consensus -> review_gate [label="Complete", condition="preferred_label=Complete"]
|
||||
final_consensus -> triage_merge [label="More work needed", condition="preferred_label=More work needed"]
|
||||
final_consensus -> triage_merge [label="More work needed"]
|
||||
|
||||
/* Phase 8: Human gate */
|
||||
review_gate -> exit [label="A) Accept"]
|
||||
|
|
|
|||
|
|
@ -122,10 +122,10 @@ digraph SemanticPort {
|
|||
start -> fetch
|
||||
|
||||
fetch -> analyze [label="Process", condition="preferred_label=process"]
|
||||
fetch -> exit [label="Done", condition="preferred_label=done"]
|
||||
fetch -> exit [label="Done"]
|
||||
|
||||
analyze -> plan [label="Port", condition="preferred_label=port"]
|
||||
analyze -> fetch [label="Skip", condition="preferred_label=skip"]
|
||||
analyze -> fetch [label="Skip"]
|
||||
|
||||
plan -> implement -> validate -> gate
|
||||
|
||||
|
|
|
|||
83
test/docs/CHECKLIST.md
Normal file
83
test/docs/CHECKLIST.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# DOT Documentation Examples Test Checklist
|
||||
|
||||
## Summary
|
||||
- 36 .dot files (29 extracted from full workflows + 7 assembled from snippets)
|
||||
- Covers 29 doc pages, 118 DOT code blocks (29 full, 89 snippets)
|
||||
- Skipped: changelog/2026-02-27 (deprecated `handler=codergen` syntax)
|
||||
|
||||
## Phase 1: Validate (`arc validate`)
|
||||
|
||||
| # | File | Status | Notes |
|
||||
|---|------|--------|-------|
|
||||
| 1 | agents/outputs/output-patterns.dot | PASS | assembled |
|
||||
| 2 | agents/prompts/pipeline.dot | PASS | added start/exit |
|
||||
| 3 | changelog/2026-03-05/new-features.dot | PASS | assembled, added fallback |
|
||||
| 4 | core-concepts/agents/backend-demo.dot | PASS | assembled |
|
||||
| 5 | core-concepts/models/example.dot | PASS | added start/exit + wiring |
|
||||
| 6 | core-concepts/workflows/my-workflow.dot | PASS | |
|
||||
| 7 | examples/clone-substack/clone-substack.dot | PASS | 578 lines |
|
||||
| 8 | examples/definition-of-done/spec-dod-multimodel.dot | PASS | fixed condition quoting + fallbacks |
|
||||
| 9 | examples/definition-of-done/spec-dod.dot | PASS | fixed condition quoting + fallbacks |
|
||||
| 10 | examples/nlspec-conformance/n-l-spec-conformance.dot | PASS | warning: goal_gate without retry_target |
|
||||
| 11 | examples/semantic-port/semantic-port.dot | PASS | added fallback edges |
|
||||
| 12 | examples/solitaire/build-solitaire.dot | PASS | warning: missing retry_target |
|
||||
| 13 | execution/context/example.dot | PASS | added start/exit |
|
||||
| 14 | execution/failures/example.dot | PASS | added start/exit |
|
||||
| 15 | execution/failures/example-02.dot | PASS | added start/exit |
|
||||
| 16 | execution/failures/example-03.dot | PASS | added start/exit |
|
||||
| 17 | execution/failures/example-04.dot | PASS | added start/exit |
|
||||
| 18 | execution/interviews/default-choice.dot | PASS | assembled |
|
||||
| 19 | execution/run-configuration/c-i.dot | PASS | added start/exit, has run.toml |
|
||||
| 20 | getting-started/why-arc/plan-implement.dot | PASS | |
|
||||
| 21 | reference/dot-language/implement-feature.dot | PASS | |
|
||||
| 22 | reference/dot-language/my-workflow.dot | PASS | |
|
||||
| 23 | tutorials/branch-loop/branch-loop.dot | PASS | |
|
||||
| 24 | tutorials/ensemble/ensemble.dot | PASS | |
|
||||
| 25 | tutorials/hello-world/hello.dot | PASS | |
|
||||
| 26 | tutorials/hello-world/sub-agent.dot | PASS | |
|
||||
| 27 | tutorials/hello-world/tool-use.dot | PASS | |
|
||||
| 28 | tutorials/multi-model/multi-model.dot | PASS | |
|
||||
| 29 | tutorials/parallel-review/parallel.dot | PASS | |
|
||||
| 30 | tutorials/plan-implement/plan-implement.dot | PASS | has @prompt stub |
|
||||
| 31 | workflows/human-in-the-loop/hitl-patterns.dot | PASS | assembled |
|
||||
| 32 | workflows/stages-and-nodes/all-node-types.dot | PASS | assembled, 15 nodes |
|
||||
| 33 | workflows/stylesheets/example.dot | PASS | |
|
||||
| 34 | workflows/transitions/transition-patterns.dot | PASS | assembled, added fallbacks |
|
||||
| 35 | workflows/variables/check.dot | PASS | has run.toml |
|
||||
| 36 | workflows/variables/example.dot | PASS | added start/exit |
|
||||
|
||||
## Phase 2: Dry Run (`arc run start --dry-run --auto-approve`)
|
||||
|
||||
| # | File | Status | Notes |
|
||||
|---|------|--------|-------|
|
||||
| 1-36 | (all) | | |
|
||||
|
||||
## Phase 3: Haiku (`arc run start --model claude-haiku-4-5 --auto-approve`)
|
||||
|
||||
| # | File | Status | Notes |
|
||||
|---|------|--------|-------|
|
||||
| 1-36 | (all) | | |
|
||||
|
||||
## Phase 4: Full (`arc run start --auto-approve`)
|
||||
|
||||
| # | File | Status | Notes |
|
||||
|---|------|--------|-------|
|
||||
| 1-36 | (all) | | |
|
||||
|
||||
## Issues Found During Validation (fixed in test DOTs)
|
||||
|
||||
1. **Condition parser doesn't support multi-word values** — `preferred_label=More fixes needed` fails parse. Fixed by using underscored values (`more_fixes_needed`). Affects: definition-of-done examples. **This is a docs bug** — the source DOTs in docs/examples/ use multi-word condition values that won't parse.
|
||||
|
||||
2. **Several "full" digraphs in docs lack start/exit nodes** — 9 extracted DOTs were minimal digraph wrappers showing graph-level attributes without start/exit nodes or wiring. Fixed by adding them in test DOTs.
|
||||
|
||||
3. **All-conditional edges need unconditional fallback** — Validator requires at least one fallback edge when a node has only conditional outgoing edges. Fixed by adding fallback edges. Affects: semantic-port, definition-of-done examples, and assembled snippet DOTs.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Run each phase:
|
||||
./test/docs/run_tests.sh validate
|
||||
./test/docs/run_tests.sh dry-run
|
||||
./test/docs/run_tests.sh haiku
|
||||
./test/docs/run_tests.sh full
|
||||
```
|
||||
33
test/docs/agents/outputs/output-patterns.dot
Normal file
33
test/docs/agents/outputs/output-patterns.dot
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Assembled from docs/agents/outputs.mdx snippets
|
||||
// Tests output context keys and routing directives
|
||||
|
||||
digraph OutputPatterns {
|
||||
graph [goal="Exercise output and routing patterns from the outputs docs page"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
// Line 25-29: Context keys from prior stages
|
||||
plan [label="Plan", prompt="Create an implementation plan."]
|
||||
implement [label="Implement", prompt="Implement the plan."]
|
||||
|
||||
// Line 68-78: Review node with routing directives
|
||||
review [
|
||||
label="Review",
|
||||
shape=tab,
|
||||
prompt="Review the implementation. If changes are needed, \
|
||||
respond with: {\"preferred_next_label\": \"fix\"}. \
|
||||
If everything looks good, respond with: \
|
||||
{\"preferred_next_label\": \"approve\"}."
|
||||
]
|
||||
|
||||
fix [label="Fix", prompt="Fix the issues found."]
|
||||
|
||||
// Wiring
|
||||
start -> plan -> implement -> review
|
||||
|
||||
review -> fix [label="Fix"]
|
||||
review -> exit [label="Approve"]
|
||||
|
||||
fix -> review
|
||||
}
|
||||
10
test/docs/agents/prompts/pipeline.dot
Normal file
10
test/docs/agents/prompts/pipeline.dot
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
digraph Pipeline {
|
||||
graph [goal="Add a /health endpoint to the API server"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
implement [prompt="Implement the following: $goal"]
|
||||
|
||||
start -> implement -> exit
|
||||
}
|
||||
28
test/docs/changelog/2026-03-05/new-features.dot
Normal file
28
test/docs/changelog/2026-03-05/new-features.dot
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Assembled from docs/changelog/2026-03-05.mdx snippets
|
||||
// Tests: condition expressions, model assignment, per-node max_visits,
|
||||
// $$ escape, and simplified handler type names
|
||||
|
||||
digraph NewFeatures {
|
||||
graph [goal="Exercise new features from the 2026-03-05 changelog"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
// Line 85: Model assignment (gpt54-pro)
|
||||
stage_a [model="gpt54-pro", type="agent", prompt="The cost is $$50 and the goal is $goal"]
|
||||
|
||||
// Line 95: Per-node loop limit
|
||||
verify [type="agent", max_visits=20, prompt="Verify the implementation."]
|
||||
|
||||
// Line 128-129: Simplified handler type names
|
||||
stage_b [type="prompt", prompt="Summarize the results."]
|
||||
|
||||
// Wiring with condition expressions (line 31)
|
||||
start -> stage_a -> verify
|
||||
|
||||
verify -> stage_b [label="Pass", condition="outcome=success"]
|
||||
verify -> stage_a [label="Retry", condition="outcome=fail"]
|
||||
verify -> exit [label="Fallback"]
|
||||
|
||||
stage_b -> exit
|
||||
}
|
||||
18
test/docs/core-concepts/agents/backend-demo.dot
Normal file
18
test/docs/core-concepts/agents/backend-demo.dot
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Assembled from docs/core-concepts/agents.mdx snippets
|
||||
// Tests backend attribute and inline vs external prompts
|
||||
|
||||
digraph BackendDemo {
|
||||
graph [goal="Exercise agent backend and prompt patterns from the agents docs page"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
// Line 47: CLI backend with explicit provider
|
||||
implement [label="Implement", backend="cli", llm_provider="anthropic"]
|
||||
|
||||
// Line 95-96: Inline prompt
|
||||
plan [label="Plan", prompt="Analyze the codebase and write a step-by-step plan."]
|
||||
|
||||
// Wiring
|
||||
start -> plan -> implement -> exit
|
||||
}
|
||||
19
test/docs/core-concepts/models/example.dot
Normal file
19
test/docs/core-concepts/models/example.dot
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
digraph Example {
|
||||
graph [
|
||||
goal="Demonstrate model stylesheet",
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-haiku-4-5; }
|
||||
.coding { llm_model: claude-sonnet-4-5; reasoning_effort: high; }
|
||||
#review { llm_model: gemini-3.1-pro-preview; }
|
||||
"
|
||||
]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
spec [label="Write Spec"]
|
||||
implement [label="Implement", class="coding"]
|
||||
review [label="Review"]
|
||||
|
||||
start -> spec -> implement -> review -> exit
|
||||
}
|
||||
12
test/docs/core-concepts/workflows/my-workflow.dot
Normal file
12
test/docs/core-concepts/workflows/my-workflow.dot
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
digraph MyWorkflow {
|
||||
graph [goal="Describe the project"]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
scan [label="Scan Files", shape=parallelogram, script="find . -maxdepth 2 -type f | head -30"]
|
||||
analyze [label="Analyze", prompt="Review the file listing. Summarize the project structure.", shape=tab]
|
||||
|
||||
start -> scan -> analyze -> exit
|
||||
}
|
||||
578
test/docs/examples/clone-substack/clone-substack.dot
Normal file
578
test/docs/examples/clone-substack/clone-substack.dot
Normal file
|
|
@ -0,0 +1,578 @@
|
|||
digraph CloneSubstack {
|
||||
graph [
|
||||
goal="Build the Substack Creator Newsletter Engine — a pure React frontend \
|
||||
(no backend) for brand-driven Substack content creation. Client-side Gemini LLM \
|
||||
integration (gemini-3-flash-preview for fast tasks, gemini-3.1-pro-preview with \
|
||||
extended thinking for important tasks, gemini-2.5-flash-lite for tests). IndexedDB \
|
||||
persistence via idb library. Setup flow with API key, company identity, voice \
|
||||
definition, and guardrails — each confirmed by gemini-3.1-pro-preview. Dashboard \
|
||||
with post history, draft management, New Post and Trending Topics access. Trending \
|
||||
Topics uses gemini-3-flash-preview with search grounding for research, \
|
||||
gemini-3.1-pro-preview synthesizes 3 writing prompts. New Post pipeline: Topic \
|
||||
(rich input) then Research (gemini-3-flash-preview search grounding, source \
|
||||
metadata) then Outline (gemini-3.1-pro-preview one-shot) then Write/Edit/Guardrails \
|
||||
(3 automatic gemini-3.1-pro-preview cycles) then Complete (serif footnoted citations \
|
||||
with attribution lineage). Demo mode replays recorded sessions through production \
|
||||
code path with fade-in prefills; ships with one bundled P&G session; cache miss \
|
||||
shows error, no API fallback. Visual design matches Substack (serif fonts, horizontal \
|
||||
dot step indicators, card primitives, accent progress bars, numbered footnotes). Test \
|
||||
infrastructure: integration tests with canned data, smoke tests with live \
|
||||
gemini-2.5-flash-lite, manual test option with real models. Deployment readiness for \
|
||||
GitHub to Railway validated by code review only — no live deployment execution.",
|
||||
rankdir=LR,
|
||||
default_max_retry=3,
|
||||
retry_target="plan_fanout",
|
||||
fallback_retry_target="plan_fanout",
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-opus-4-6; llm_provider: anthropic; }
|
||||
.hard { llm_model: gpt-5.3-codex; llm_provider: openai; }
|
||||
.verify { llm_model: claude-opus-4-6; llm_provider: anthropic; }
|
||||
.branch-a { llm_model: claude-opus-4-6; llm_provider: anthropic; }
|
||||
.branch-b { llm_model: gemini-3-flash-preview; llm_provider: gemini; }
|
||||
"
|
||||
]
|
||||
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
// =========================================================================
|
||||
// Bootstrap
|
||||
// =========================================================================
|
||||
|
||||
subgraph cluster_bootstrap {
|
||||
label="Bootstrap"
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
|
||||
check_toolchain [
|
||||
shape=parallelogram,
|
||||
label="Check Toolchain",
|
||||
max_retries=0,
|
||||
script="command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1 \
|
||||
&& node --version && npm --version"
|
||||
]
|
||||
|
||||
expand_spec [
|
||||
label="Expand Spec",
|
||||
prompt="Goal: $goal\n\n\
|
||||
The project specification is at substack-spec-v01.md and the Definition of Done \
|
||||
is at substack-dod-v01.md. The UI flow diagram is at substack-spec-v01-ui.gv.\n\n\
|
||||
Read all three files. Scratch artifacts go under .workflow/.\n\n\
|
||||
If .workflow/spec.md does not exist or is a placeholder, copy the spec verbatim \
|
||||
to .workflow/spec.md, appending a reference to the UI flow diagram. If \
|
||||
.workflow/definition_of_done.md does not exist or is a placeholder, copy the DoD \
|
||||
verbatim to .workflow/definition_of_done.md. If both already exist and are \
|
||||
adequate, skip."
|
||||
]
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Planning Fanout
|
||||
// =========================================================================
|
||||
|
||||
subgraph cluster_planning {
|
||||
label="Planning Fanout"
|
||||
node [shape=box]
|
||||
|
||||
plan_fanout [shape=component, label="Plan Fan-Out"]
|
||||
|
||||
plan_a [
|
||||
label="Plan A",
|
||||
class="branch-a",
|
||||
prompt="Goal: $goal\n\n\
|
||||
Read .workflow/spec.md and .workflow/definition_of_done.md. If those files do not \
|
||||
exist, fall back to reading substack-spec-v01.md and substack-dod-v01.md directly. \
|
||||
If .workflow/postmortem_latest.md exists, incorporate its lessons.\n\n\
|
||||
Create an implementation plan for the Substack Creator Newsletter Engine covering \
|
||||
all deliverables and acceptance criteria from the DoD. Be specific about:\n\
|
||||
- React project setup (Vite + TypeScript + idb + @google/generative-ai SDK)\n\
|
||||
- Module decomposition with file paths and estimated sizes (~200-500 lines each)\n\
|
||||
- Core infrastructure: LLM client with structured JSON output and retry/backoff, \
|
||||
IndexedDB persistence layer, shared UI components (rich input, card, progress bar, \
|
||||
step indicators)\n\
|
||||
- Feature modules: Setup flow, Dashboard, Trending Topics, New Post pipeline, \
|
||||
Demo mode\n\
|
||||
- Test infrastructure: integration (canned data), smoke (gemini-2.5-flash-lite), \
|
||||
manual (real models)\n\
|
||||
- Deployment config: Railway config, validation scripts\n\
|
||||
- Build/validate scripts: validate-build.sh, validate-fmt.sh, validate-test.sh, \
|
||||
validate-browser.sh, fix-fmt.sh, validate-artifacts.sh\n\
|
||||
- Visual design: Substack-like serif styling, no spinners\n\n\
|
||||
Specify dependency ordering between modules.\n\n\
|
||||
Write to .workflow/plan_a.md."
|
||||
]
|
||||
|
||||
plan_b [
|
||||
label="Plan B",
|
||||
class="branch-b",
|
||||
prompt="Goal: $goal\n\n\
|
||||
Read .workflow/spec.md and .workflow/definition_of_done.md. If those files do not \
|
||||
exist, fall back to reading substack-spec-v01.md and substack-dod-v01.md directly. \
|
||||
If .workflow/postmortem_latest.md exists, incorporate its lessons.\n\n\
|
||||
Create an implementation plan for the Substack Creator Newsletter Engine covering \
|
||||
all deliverables and acceptance criteria from the DoD. Be specific about:\n\
|
||||
- React project setup (Vite + TypeScript + idb + @google/generative-ai SDK)\n\
|
||||
- Module decomposition with file paths and estimated sizes (~200-500 lines each)\n\
|
||||
- Core infrastructure: LLM client with structured JSON output and retry/backoff, \
|
||||
IndexedDB persistence layer, shared UI components (rich input, card, progress bar, \
|
||||
step indicators)\n\
|
||||
- Feature modules: Setup flow, Dashboard, Trending Topics, New Post pipeline, \
|
||||
Demo mode\n\
|
||||
- Test infrastructure: integration (canned data), smoke (gemini-2.5-flash-lite), \
|
||||
manual (real models)\n\
|
||||
- Deployment config: Railway config, validation scripts\n\
|
||||
- Build/validate scripts: validate-build.sh, validate-fmt.sh, validate-test.sh, \
|
||||
validate-browser.sh, fix-fmt.sh, validate-artifacts.sh\n\
|
||||
- Visual design: Substack-like serif styling, no spinners\n\n\
|
||||
Specify dependency ordering between modules.\n\n\
|
||||
Write to .workflow/plan_b.md."
|
||||
]
|
||||
|
||||
debate [
|
||||
label="Debate & Consolidate",
|
||||
prompt="Synthesize the two implementation plans into a single best-of-breed \
|
||||
final plan.\n\n\
|
||||
Read branch outputs via parallel_results.json. If parallel_results.json is missing, \
|
||||
fall back to reading .workflow/plan_a.md and .workflow/plan_b.md.\n\n\
|
||||
If .workflow/postmortem_latest.md exists, read it FIRST. The postmortem contains \
|
||||
root-cause analysis and concrete fixes from the previous iteration. The final plan \
|
||||
MUST be adjusted to address every issue identified in the postmortem — add new \
|
||||
steps, change approaches, or reorder work as needed. Do not simply re-emit the \
|
||||
same plan that failed.\n\n\
|
||||
Also read .workflow/implementation_log.md and .workflow/verify_fidelity.md if they \
|
||||
exist, to understand what worked and what failed in the previous iteration.\n\n\
|
||||
Read .workflow/spec.md and .workflow/definition_of_done.md for context. If those \
|
||||
files do not exist, fall back to reading substack-spec-v01.md and \
|
||||
substack-dod-v01.md directly. Resolve conflicts between plans. Ensure dependency \
|
||||
order is correct. Pick the most detailed and actionable approach for each module. \
|
||||
The final plan must produce a work queue of bounded modules (~200-500 lines each), \
|
||||
ordered so core infrastructure items come first (lower IDs), features next, and \
|
||||
tests/deployment last.\n\n\
|
||||
Write the final plan to .workflow/plan_final.md."
|
||||
]
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Implement
|
||||
// =========================================================================
|
||||
|
||||
subgraph cluster_implement {
|
||||
label="Implement"
|
||||
|
||||
implement [
|
||||
class="hard",
|
||||
max_tokens=32768,
|
||||
label="Implement",
|
||||
prompt="Goal: $goal\n\n\
|
||||
Read .workflow/plan_final.md, .workflow/spec.md, and \
|
||||
.workflow/definition_of_done.md. If the spec or DoD files do not exist at those \
|
||||
paths, fall back to reading substack-spec-v01.md and substack-dod-v01.md directly.\n\n\
|
||||
BEFORE ANYTHING ELSE: check if .workflow/verify_errors.log exists. If it does, \
|
||||
read it — it contains the exact commands that failed and their error output from \
|
||||
the verify chain. Fix every error listed in that file, then delete \
|
||||
.workflow/verify_errors.log when all fixes are applied. Do NOT regenerate working \
|
||||
code — only fix the specific errors.\n\n\
|
||||
Also check if .workflow/verify_fidelity.md exists. If it does, read it — it \
|
||||
contains per-AC pass/fail verdicts from the fidelity check. Fix every failing AC \
|
||||
listed in that file.\n\n\
|
||||
If .workflow/postmortem_latest.md exists, read it and fix ONLY identified gaps — \
|
||||
do NOT regenerate working code. On repair passes, read and fix existing files \
|
||||
rather than skipping them.\n\n\
|
||||
Implement the complete Substack Creator Newsletter Engine as a single pass. On a \
|
||||
fresh pass (no postmortem), check if target files already exist on disk and are \
|
||||
non-empty — if so, skip those files. Implement each module with complete, \
|
||||
functional code — no stubs, no placeholders, no TODO comments. Follow the plan \
|
||||
and spec precisely.\n\n\
|
||||
Implementation order (core infrastructure first, then features, then tests/deploy):\n\n\
|
||||
1. Project scaffold — package.json, vite.config.ts, tsconfig.json, index.html, \
|
||||
src/main.tsx, src/App.tsx. Install dependencies: react, react-dom, \
|
||||
react-router-dom, idb, @google/generative-ai. Write ALL validation scripts:\n\
|
||||
- scripts/validate-build.sh: runs npm run build, checks dist/ exists\n\
|
||||
- scripts/validate-fmt.sh: runs npx prettier --check src/\n\
|
||||
- scripts/validate-test.sh: runs integration scenarios first, then smoke, \
|
||||
writes evidence + .workflow/test-evidence/latest/manifest.json even on failure\n\
|
||||
- scripts/validate-browser.sh: runs browser verification and captures artifacts\n\
|
||||
- scripts/fix-fmt.sh: runs npx prettier --write src/\n\
|
||||
- scripts/validate-artifacts.sh: verifies manifest scenario IDs match DoD \
|
||||
integration scenarios\n\
|
||||
All scripts: #!/bin/sh, set -e, POSIX sh failure trap.\n\n\
|
||||
2. LLM client — src/lib/llm.ts, src/lib/llm-schemas.ts: structured JSON output \
|
||||
with schema enforcement, retry with error feedback and intelligent backoff, model \
|
||||
switching (gemini-3-flash-preview/gemini-3.1-pro-preview/gemini-2.5-flash-lite), \
|
||||
client-side API key.\n\n\
|
||||
3. Persistence — src/lib/db.ts, src/lib/types.ts: IndexedDB via idb with stores \
|
||||
for configuration (API key, company, voice, guardrails), drafts, sessions (all \
|
||||
inputs/LLM responses/intermediate state), post history (Markdown + attribution). \
|
||||
All data persists unless user resets.\n\n\
|
||||
4. Shared UI — src/components/RichInput.tsx, Card.tsx, ProgressBar.tsx, \
|
||||
StepIndicator.tsx, src/styles/global.css.\n\n\
|
||||
5. Setup flow — src/pages/Settings.tsx and step components: API key, company \
|
||||
(rich input + gemini-3.1-pro-preview confirm + back), voice, guardrails. Parallel \
|
||||
completion, status icons. Reset everything with confirmation.\n\n\
|
||||
6. Dashboard — src/pages/Dashboard.tsx: New Post button, Trending Topics button, \
|
||||
Settings link, post history, draft resume.\n\n\
|
||||
7. Trending Topics — src/pages/TrendingTopics.tsx: parallel gemini-3-flash-preview \
|
||||
search grounding queries, trend visualization, 3 gemini-3.1-pro-preview writing \
|
||||
prompts, navigate to New Post prefilled.\n\n\
|
||||
8. New Post — src/pages/NewPost.tsx with step components: Topic (rich input), \
|
||||
Research (gemini-3-flash-preview search grounding, source cards with \
|
||||
URL/title/author/date, highlight/delete), Outline (gemini-3.1-pro-preview one-shot, \
|
||||
accept/back), Write (3 automatic gemini-3.1-pro-preview cycles: Write with \
|
||||
citations, Edit for style, Guardrails-only), Complete (serif post with numbered \
|
||||
footnotes, linked sources, attribution lineage).\n\n\
|
||||
9. Demo mode — src/lib/demo.ts, src/pages/DemoMode.tsx, \
|
||||
src/demo/bundled-session.json: session recording, replay through production path \
|
||||
(fade-in prefills, highlight next button), bundled P&G session, cache-miss error \
|
||||
with no API fallback.\n\n\
|
||||
10. Test infrastructure — src/__tests__/: integration with canned data, smoke with \
|
||||
gemini-2.5-flash-lite, manual mode option.\n\n\
|
||||
11. Deploy config — railway.json or equivalent, deployment docs.\n\n\
|
||||
Ensure App.tsx routing includes all pages. Verify imports/exports are consistent. \
|
||||
Run npm install. Fix TypeScript errors.\n\n\
|
||||
Log progress to .workflow/implementation_log.md.\n\n\
|
||||
PRE-EXIT VERIFICATION: if .workflow/postmortem_latest.md exists, run \
|
||||
sh scripts/validate-build.sh and re-read targeted files to confirm fixes."
|
||||
]
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Verify Chain
|
||||
// =========================================================================
|
||||
|
||||
subgraph cluster_verify {
|
||||
label="Verify"
|
||||
|
||||
fix_fmt [
|
||||
shape=parallelogram,
|
||||
label="Fix Format",
|
||||
max_retries=0,
|
||||
script="sh scripts/fix-fmt.sh 2>&1 || { printf '\\n=== VERIFY FAILURE: \
|
||||
fix-fmt ===\\n%s\\n' \"$(cat /tmp/fix-fmt.log 2>/dev/null || echo 'script missing \
|
||||
or produced no output')\" >> .workflow/verify_errors.log; exit 1; }"
|
||||
]
|
||||
|
||||
verify_fmt [
|
||||
shape=parallelogram,
|
||||
label="Check Format",
|
||||
max_retries=0,
|
||||
script="sh scripts/validate-fmt.sh 2>&1 | tee /tmp/validate-fmt.log; \
|
||||
test ${PIPESTATUS[0]} -eq 0 || { printf '\\n=== VERIFY FAILURE: validate-fmt \
|
||||
===\\n%s\\n' \"$(tail -30 /tmp/validate-fmt.log)\" >> .workflow/verify_errors.log; \
|
||||
exit 1; }"
|
||||
]
|
||||
gate_fmt [shape=diamond, label="Fmt OK?"]
|
||||
|
||||
verify_build [
|
||||
shape=parallelogram,
|
||||
label="Check Build",
|
||||
script="sh scripts/validate-build.sh 2>&1 | tee /tmp/validate-build.log; \
|
||||
test ${PIPESTATUS[0]} -eq 0 || { printf '\\n=== VERIFY FAILURE: validate-build \
|
||||
===\\n%s\\n' \"$(tail -50 /tmp/validate-build.log)\" >> .workflow/verify_errors.log; \
|
||||
exit 1; }"
|
||||
]
|
||||
gate_build [shape=diamond, label="Build OK?"]
|
||||
|
||||
verify_test [
|
||||
shape=parallelogram,
|
||||
label="Run Tests",
|
||||
script="sh scripts/validate-test.sh 2>&1 | tee /tmp/validate-test.log; \
|
||||
test ${PIPESTATUS[0]} -eq 0 || { printf '\\n=== VERIFY FAILURE: validate-test \
|
||||
===\\n%s\\n' \"$(tail -50 /tmp/validate-test.log)\" >> .workflow/verify_errors.log; \
|
||||
exit 1; }"
|
||||
]
|
||||
gate_test [shape=diamond, label="Tests OK?"]
|
||||
|
||||
verify_browser [
|
||||
shape=parallelogram,
|
||||
label="Check Browser",
|
||||
script="sh scripts/validate-browser.sh 2>&1 | tee \
|
||||
/tmp/validate-browser.log; test ${PIPESTATUS[0]} -eq 0 || { printf '\\n=== VERIFY \
|
||||
FAILURE: validate-browser ===\\n%s\\n' \"$(tail -50 /tmp/validate-browser.log)\" \
|
||||
>> .workflow/verify_errors.log; exit 1; }"
|
||||
]
|
||||
gate_browser [shape=diamond, label="Browser OK?"]
|
||||
|
||||
verify_artifacts [
|
||||
shape=parallelogram,
|
||||
label="Check Artifacts",
|
||||
max_retries=0,
|
||||
script="sh scripts/validate-artifacts.sh 2>&1 | tee \
|
||||
/tmp/validate-artifacts.log; test ${PIPESTATUS[0]} -eq 0 || { printf '\\n=== \
|
||||
VERIFY FAILURE: validate-artifacts ===\\n%s\\n' \"$(tail -30 \
|
||||
/tmp/validate-artifacts.log)\" >> .workflow/verify_errors.log; exit 1; }"
|
||||
]
|
||||
gate_artifacts [shape=diamond, label="Artifacts OK?"]
|
||||
|
||||
verify_fidelity [
|
||||
label="Verify Fidelity",
|
||||
class="verify",
|
||||
prompt="Read .workflow/spec.md, .workflow/definition_of_done.md, \
|
||||
.workflow/verify_fidelity.md (if present), \
|
||||
.workflow/test-evidence/latest/manifest.json, and relevant implementation files.\n\n\
|
||||
Evaluate these grouped acceptance checks and map each to concrete file paths:\n\
|
||||
AC1: src/**/settings* and src/**/router* and src/**/indexeddb* - first-run routing, \
|
||||
setup flow, persistence.\n\
|
||||
AC2: src/**/dashboard* and src/**/history* and src/**/draft* - dashboard actions \
|
||||
and resume/view flows.\n\
|
||||
AC3: src/**/trending* and src/**/research* - grounded research, deterministic \
|
||||
trends, prompt handoff.\n\
|
||||
AC4: src/**/new-post* and src/**/outline* and src/**/write* and src/**/complete* - \
|
||||
full Topic->Complete pipeline with automatic write cycles.\n\
|
||||
AC5: src/**/citation* and src/**/markdown* - citation lineage, footnote rendering, \
|
||||
attribution persistence.\n\
|
||||
AC6: src/**/demo* and src/demo/** - session picker/replay, bundled P&G demo, \
|
||||
cache-miss no-fallback behavior.\n\
|
||||
AC7: src/**/llm* and src/**/schema* - structured outputs, retry/backoff, \
|
||||
production/test model intent.\n\
|
||||
AC8: scripts/validate-build.sh and railway.json/Procfile/README* - \
|
||||
build/deploy-readiness by static review only, no live deployment execution.\n\
|
||||
AC9: scripts/validate-test.sh and scripts/validate-browser.sh and test sources - \
|
||||
integration before smoke, manual mode option, browser evidence capture.\n\
|
||||
AC10: .workflow/test-evidence/latest/manifest.json and \
|
||||
.workflow/test-evidence/latest/** - IT-1..IT-12 manifest coverage and required \
|
||||
artifact types.\n\
|
||||
AC11: src/**/style* and src/**/card* and src/**/progress* - Substack-like visual \
|
||||
contract including bars, cards, and serif post preview.\n\n\
|
||||
Write .workflow/verify_fidelity.md with pass/fail verdict and evidence per \
|
||||
AC1..AC11.\n\n\
|
||||
On ANY failure: also append to .workflow/verify_errors.log with the header \
|
||||
'=== VERIFY FAILURE: verify_fidelity ===' followed by the list of failing ACs \
|
||||
and their specific issues, so the implement node can read the consolidated \
|
||||
error log.\n\n\
|
||||
If all ACs pass, include in your response:\n\
|
||||
{\"context_updates\": {\"all_acs_pass\": \"true\"}}\n\n\
|
||||
If any AC fails, include in your response:\n\
|
||||
{\"context_updates\": {\"all_acs_pass\": \"false\"}}"
|
||||
]
|
||||
gate_fidelity [shape=diamond, label="Fidelity OK?"]
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Review Fanout
|
||||
// =========================================================================
|
||||
|
||||
subgraph cluster_review {
|
||||
label="Review Fanout"
|
||||
node [shape=box]
|
||||
|
||||
review_fanout [shape=component, label="Review Fan-Out"]
|
||||
|
||||
review_a [
|
||||
label="Review A",
|
||||
class="branch-a",
|
||||
prompt="Review the Substack Creator Newsletter Engine implementation \
|
||||
against .workflow/definition_of_done.md.\n\n\
|
||||
Read the DoD for acceptance criteria. Read all implementation source files and \
|
||||
.workflow/test-evidence/latest/manifest.json.\n\n\
|
||||
## MANDATORY: Browser verification\n\
|
||||
You MUST verify the app works in a real browser. Do not trust code reading alone.\n\
|
||||
1. Run: npm run build (must exit 0)\n\
|
||||
2. Start the preview server: npx vite preview --port 4567 &\n\
|
||||
3. Wait 2 seconds, then use curl to fetch http://localhost:4567/ and verify it \
|
||||
returns HTML with a root div\n\
|
||||
4. Check that the HTML references JS and CSS bundles\n\
|
||||
5. Kill the preview server when done\n\
|
||||
6. Check browser artifacts in .workflow/test-evidence/latest/ — screenshots must \
|
||||
be real rendered pages (not 1x1 placeholders). If screenshot files are under 5KB, \
|
||||
they are fake. REJECT.\n\
|
||||
7. Check that playwright-report or equivalent browser test output exists and shows \
|
||||
real test execution\n\n\
|
||||
If browser verification fails or artifacts are fake, REJECT immediately.\n\n\
|
||||
## Code and AC verification\n\
|
||||
Check every AC group (AC1 through AC11):\n\n\
|
||||
AC1: Build exits 0, static assets produced, deployment config present and coherent \
|
||||
(review only, no live deploy)\n\
|
||||
AC2: IndexedDB persistence for API key, config, posts, drafts, sessions, \
|
||||
attribution mappings across reloads\n\
|
||||
AC3: Structured JSON output with retry/backoff, correct model routing \
|
||||
(gemini-3-flash-preview/gemini-3.1-pro-preview/gemini-2.5-flash-lite), \
|
||||
client-side key\n\
|
||||
AC4: Parallel setup (any order), status icons, rich input (text/upload/link), \
|
||||
gemini-3.1-pro-preview confirmation, back button\n\
|
||||
AC5: Dashboard with New Post and Trending Topics buttons, Settings link, post \
|
||||
history, draft resume\n\
|
||||
AC6: Trending Topics: parallel gemini-3-flash-preview search research, trend \
|
||||
visualization, 3 gemini-3.1-pro-preview writing prompts, navigate to New Post\n\
|
||||
AC7: Full post pipeline with source metadata, highlight/delete, one-shot outline, \
|
||||
3 automatic write cycles, citations with attribution lineage\n\
|
||||
AC8: Demo replay through production path, fade-in/highlight, bundled P&G session, \
|
||||
cache-miss error\n\
|
||||
AC9: Validation scripts and runtime evidence contract for build/test/browser checks\n\
|
||||
AC10: IT-1..IT-12 evidence manifest coverage and artifact completeness\n\
|
||||
AC11: Substack visual design: serif fonts, step dots, card primitive, accent \
|
||||
progress bars, no spinners, footnoted post\n\n\
|
||||
Verdict: APPROVED (all criteria met with evidence) or REJECTED (specific gaps \
|
||||
by AC ID).\n\
|
||||
Write to .workflow/review_a.md."
|
||||
]
|
||||
|
||||
review_b [
|
||||
label="Review B",
|
||||
class="branch-b",
|
||||
prompt="Review the Substack Creator Newsletter Engine implementation \
|
||||
against .workflow/definition_of_done.md.\n\n\
|
||||
Read the DoD for acceptance criteria. Read all implementation source files and \
|
||||
.workflow/test-evidence/latest/manifest.json.\n\n\
|
||||
## MANDATORY: Browser verification\n\
|
||||
You MUST verify the app works in a real browser. Do not trust code reading alone.\n\
|
||||
1. Run: npm run build (must exit 0)\n\
|
||||
2. Start the preview server: npx vite preview --port 4568 &\n\
|
||||
3. Wait 2 seconds, then use curl to fetch http://localhost:4568/ and verify it \
|
||||
returns HTML with a root div\n\
|
||||
4. Check that the HTML references JS and CSS bundles\n\
|
||||
5. Kill the preview server when done\n\
|
||||
6. Check browser artifacts in .workflow/test-evidence/latest/ — screenshots must \
|
||||
be real rendered pages (not 1x1 placeholders). If screenshot files are under 5KB, \
|
||||
they are fake. REJECT.\n\
|
||||
7. Check that playwright-report or equivalent browser test output exists and shows \
|
||||
real test execution\n\n\
|
||||
If browser verification fails or artifacts are fake, REJECT immediately.\n\n\
|
||||
## Code and AC verification\n\
|
||||
Check every AC group (AC1 through AC11):\n\n\
|
||||
AC1: Build exits 0, static assets produced, deployment config present and coherent \
|
||||
(review only, no live deploy)\n\
|
||||
AC2: IndexedDB persistence for API key, config, posts, drafts, sessions, \
|
||||
attribution mappings across reloads\n\
|
||||
AC3: Structured JSON output with retry/backoff, correct model routing \
|
||||
(gemini-3-flash-preview/gemini-3.1-pro-preview/gemini-2.5-flash-lite), \
|
||||
client-side key\n\
|
||||
AC4: Parallel setup (any order), status icons, rich input (text/upload/link), \
|
||||
gemini-3.1-pro-preview confirmation, back button\n\
|
||||
AC5: Dashboard with New Post and Trending Topics buttons, Settings link, post \
|
||||
history, draft resume\n\
|
||||
AC6: Trending Topics: parallel gemini-3-flash-preview search research, trend \
|
||||
visualization, 3 gemini-3.1-pro-preview writing prompts, navigate to New Post\n\
|
||||
AC7: Full post pipeline with source metadata, highlight/delete, one-shot outline, \
|
||||
3 automatic write cycles, citations with attribution lineage\n\
|
||||
AC8: Demo replay through production path, fade-in/highlight, bundled P&G session, \
|
||||
cache-miss error\n\
|
||||
AC9: Validation scripts and runtime evidence contract for build/test/browser checks\n\
|
||||
AC10: IT-1..IT-12 evidence manifest coverage and artifact completeness\n\
|
||||
AC11: Substack visual design: serif fonts, step dots, card primitive, accent \
|
||||
progress bars, no spinners, footnoted post\n\n\
|
||||
Verdict: APPROVED (all criteria met with evidence) or REJECTED (specific gaps \
|
||||
by AC ID).\n\
|
||||
Write to .workflow/review_b.md."
|
||||
]
|
||||
|
||||
review_consensus [
|
||||
label="Review Consensus",
|
||||
goal_gate=true,
|
||||
retry_target="postmortem",
|
||||
prompt="Synthesize the two reviews into a consensus verdict.\n\n\
|
||||
Read branch outputs via parallel_results.json. If parallel_results.json is \
|
||||
missing, fall back to reading .workflow/review_a.md and .workflow/review_b.md.\n\n\
|
||||
Read .workflow/definition_of_done.md for acceptance criteria reference.\n\n\
|
||||
Consensus rules:\n\
|
||||
- Both APPROVED with no critical gaps: the implementation passes\n\
|
||||
- Any critical gap identified by either reviewer: rejected with specific AC IDs\n\
|
||||
- Mixed verdicts: rejected with gaps enumerated\n\n\
|
||||
Write to .workflow/review_consensus.md.\n\n\
|
||||
If approved, respond with:\n\
|
||||
{\"preferred_next_label\": \"approved\"}\n\n\
|
||||
If rejected, respond with:\n\
|
||||
{\"preferred_next_label\": \"rejected\"}"
|
||||
]
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Postmortem
|
||||
// =========================================================================
|
||||
|
||||
subgraph cluster_postmortem {
|
||||
label="Postmortem"
|
||||
|
||||
postmortem [
|
||||
label="Postmortem",
|
||||
prompt="Analyze the failure and guide the next repair iteration.\n\n\
|
||||
Read (if they exist):\n\
|
||||
- .workflow/review_consensus.md\n\
|
||||
- .workflow/verify_fidelity.md\n\
|
||||
- .workflow/implementation_log.md\n\
|
||||
- .workflow/test-evidence/latest/manifest.json\n\
|
||||
- Evidence files referenced by manifest entries for failed or suspicious IT \
|
||||
scenarios\n\
|
||||
- Branch review outputs via parallel_results.json (if available)\n\n\
|
||||
Output to .workflow/postmortem_latest.md (overwrite previous):\n\
|
||||
- Root causes of failure\n\
|
||||
- What works and must be preserved\n\
|
||||
- What failed and must be fixed\n\
|
||||
- Concrete next changes (specific files, specific fixes)\n\
|
||||
- Evidence file paths read (or explicit reason each was skipped)\n\
|
||||
- Do NOT direct from-scratch restart — preserve working code\n\n\
|
||||
PROGRESS DETECTION (required):\n\
|
||||
Extract current failing AC IDs from verify_fidelity.md or review outputs. \
|
||||
Compare with previous iteration and note whether progress was made \
|
||||
(fewer/different failing ACs) or zero progress (identical set).\n\n\
|
||||
OUTCOME CLASSIFICATION:\n\
|
||||
- replan: default — always routes back through planning so the plan can be \
|
||||
adjusted based on this postmortem\n\
|
||||
- needs_toolchain: environment/bootstrap/toolchain issue detected (routes to \
|
||||
check_toolchain)\n\n\
|
||||
Respond with exactly one of:\n\
|
||||
{\"preferred_next_label\": \"replan\", \"context_updates\": \
|
||||
{\"last_failing_acs\": \"AC1,AC7\"}}\n\
|
||||
{\"preferred_next_label\": \"needs_toolchain\", \"context_updates\": \
|
||||
{\"last_failing_acs\": \"AC1,AC7\"}}"
|
||||
]
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Edges
|
||||
// =========================================================================
|
||||
|
||||
// Bootstrap
|
||||
start -> check_toolchain
|
||||
check_toolchain -> expand_spec [condition="outcome=success"]
|
||||
check_toolchain -> check_toolchain [condition="outcome=fail && context.failure_class=transient_infra", loop_restart=true]
|
||||
check_toolchain -> postmortem [condition="outcome=fail && context.failure_class!=transient_infra"]
|
||||
check_toolchain -> postmortem
|
||||
|
||||
expand_spec -> plan_fanout
|
||||
|
||||
// Planning
|
||||
plan_fanout -> plan_a
|
||||
plan_fanout -> plan_b
|
||||
plan_a -> debate
|
||||
plan_b -> debate
|
||||
debate -> implement
|
||||
|
||||
// Implement -> Verify chain
|
||||
implement -> fix_fmt
|
||||
|
||||
// Verify chain — failures go directly back to implement (errors logged to .workflow/verify_errors.log)
|
||||
fix_fmt -> verify_fmt
|
||||
verify_fmt -> gate_fmt
|
||||
gate_fmt -> verify_build [condition="outcome=success"]
|
||||
gate_fmt -> implement
|
||||
|
||||
verify_build -> gate_build
|
||||
gate_build -> verify_test [condition="outcome=success"]
|
||||
gate_build -> implement
|
||||
|
||||
verify_test -> gate_test
|
||||
gate_test -> verify_browser [condition="outcome=success"]
|
||||
gate_test -> implement
|
||||
|
||||
verify_browser -> gate_browser
|
||||
gate_browser -> verify_artifacts [condition="outcome=success"]
|
||||
gate_browser -> implement
|
||||
|
||||
verify_artifacts -> gate_artifacts
|
||||
gate_artifacts -> verify_fidelity [condition="outcome=success"]
|
||||
gate_artifacts -> implement
|
||||
|
||||
verify_fidelity -> gate_fidelity
|
||||
gate_fidelity -> review_fanout [condition="context.all_acs_pass=true"]
|
||||
gate_fidelity -> implement
|
||||
|
||||
// Review
|
||||
review_fanout -> review_a
|
||||
review_fanout -> review_b
|
||||
review_a -> review_consensus
|
||||
review_b -> review_consensus
|
||||
review_consensus -> exit [label="Approved", condition="preferred_label=approved"]
|
||||
review_consensus -> postmortem [label="Rejected"]
|
||||
|
||||
// Postmortem recovery routing
|
||||
postmortem -> check_toolchain [label="Toolchain", condition="preferred_label=needs_toolchain"]
|
||||
postmortem -> plan_fanout [label="Replan"]
|
||||
}
|
||||
599
test/docs/examples/definition-of-done/spec-dod-multimodel.dot
Normal file
599
test/docs/examples/definition-of-done/spec-dod-multimodel.dot
Normal file
|
|
@ -0,0 +1,599 @@
|
|||
digraph SpecDoDMultiModel {
|
||||
graph [
|
||||
goal="Satisfy every Definition of Done checkbox across both specs (unified-llm-spec.md, coding-agent-loop-spec.md). The implementation is in Rust under crates/. Do NOT modify the spec files. Only modify implementation code. Uses multi-model consensus: Opus 4.6 and GPT-5.2 compete on audits and planning, GPT-5.2-codex and Opus 4.6 alternate on implementation.",
|
||||
default_max_retry="3",
|
||||
retry_target="triage_merge",
|
||||
default_fidelity="full",
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-opus-4-6; llm_provider: anthropic; }
|
||||
.opus { llm_model: claude-opus-4-6; llm_provider: anthropic; reasoning_effort: high; }
|
||||
.gpt { llm_model: gpt-5.2; llm_provider: openai; reasoning_effort: high; }
|
||||
.codex { llm_model: gpt-5.2-codex; llm_provider: openai; reasoning_effort: high; }
|
||||
.merge { llm_model: claude-opus-4-6; llm_provider: anthropic; reasoning_effort: high; }
|
||||
"
|
||||
]
|
||||
|
||||
start [shape=Mdiamond]
|
||||
exit [shape=Msquare]
|
||||
|
||||
/*========================================================================
|
||||
* PHASE 1 — Dual Independent Audits (interleaved, fidelity-isolated)
|
||||
*
|
||||
* Each spec is audited by both models before moving to the next.
|
||||
* Audit nodes use fidelity="truncate" so they only see the graph goal
|
||||
* and NOT each other's responses — prevents anchoring bias.
|
||||
* Full responses are still stored as response.<node_id> for later use.
|
||||
*======================================================================*/
|
||||
|
||||
/* ---- LLM spec: both models ---- */
|
||||
|
||||
audit_llm_opus [
|
||||
label="Opus: Audit LLM DoD",
|
||||
shape=box,
|
||||
class="opus",
|
||||
fidelity="truncate",
|
||||
prompt="Read docs/specs/unified-llm-spec.md Section 8 (Definition of Done) in full. Then read every source file under crates/llm/src/.
|
||||
|
||||
For EACH checkbox in sections 8.1 through 8.10, evaluate whether the current Rust implementation satisfies it. Be strict — a checkbox is only checked if the feature is fully implemented and would work correctly at runtime.
|
||||
|
||||
Respond with ONLY a JSON object (no prose) -- don't write it out as a file:
|
||||
{
|
||||
\"spec\": \"unified-llm\",
|
||||
\"model\": \"opus\",
|
||||
\"sections\": {
|
||||
\"8.1\": { \"title\": \"Core Infrastructure\", \"items\": [ {\"text\": \"...\", \"pass\": true/false, \"reason\": \"...\"} ] },
|
||||
...
|
||||
},
|
||||
\"total\": N,
|
||||
\"passed\": M,
|
||||
\"failed\": K,
|
||||
\"failed_items\": [ {\"section\": \"8.2\", \"text\": \"...\", \"reason\": \"...\"} ]
|
||||
}
|
||||
|
||||
Be thorough. Check every single checkbox."
|
||||
]
|
||||
|
||||
audit_llm_gpt [
|
||||
label="GPT-5.2: Audit LLM DoD",
|
||||
shape=box,
|
||||
class="gpt",
|
||||
fidelity="truncate",
|
||||
prompt="Read docs/specs/unified-llm-spec.md Section 8 (Definition of Done) in full. Then read every source file under crates/llm/src/.
|
||||
|
||||
For EACH checkbox in sections 8.1 through 8.10, evaluate whether the current Rust implementation satisfies it. Be strict — a checkbox is only checked if the feature is fully implemented and would work correctly at runtime.
|
||||
|
||||
Respond with ONLY a JSON object (no prose) -- don't write it out as a file:
|
||||
{
|
||||
\"spec\": \"unified-llm\",
|
||||
\"model\": \"gpt-5.2\",
|
||||
\"sections\": {
|
||||
\"8.1\": { \"title\": \"Core Infrastructure\", \"items\": [ {\"text\": \"...\", \"pass\": true/false, \"reason\": \"...\"} ] },
|
||||
...
|
||||
},
|
||||
\"total\": N,
|
||||
\"passed\": M,
|
||||
\"failed\": K,
|
||||
\"failed_items\": [ {\"section\": \"8.2\", \"text\": \"...\", \"reason\": \"...\"} ]
|
||||
}
|
||||
|
||||
Be thorough. Check every single checkbox."
|
||||
]
|
||||
|
||||
/* ---- Agent spec: both models ---- */
|
||||
|
||||
audit_agent_opus [
|
||||
label="Opus: Audit Agent DoD",
|
||||
shape=box,
|
||||
class="opus",
|
||||
fidelity="truncate",
|
||||
prompt="Read docs/specs/coding-agent-loop-spec.md Section 9 (Definition of Done) in full. Then read every source file under crates/agent/.
|
||||
|
||||
For EACH checkbox in sections 9.1 through 9.13, evaluate whether the current Rust implementation satisfies it. Be strict.
|
||||
|
||||
Respond with ONLY a JSON object (no prose) -- don't write it out as a file:
|
||||
{
|
||||
\"spec\": \"coding-agent-loop\",
|
||||
\"model\": \"opus\",
|
||||
\"sections\": { ... },
|
||||
\"total\": N,
|
||||
\"passed\": M,
|
||||
\"failed\": K,
|
||||
\"failed_items\": [ {\"section\": \"9.1\", \"text\": \"...\", \"reason\": \"...\"} ]
|
||||
}
|
||||
|
||||
Be thorough. Check every single checkbox."
|
||||
]
|
||||
|
||||
audit_agent_gpt [
|
||||
label="GPT-5.2: Audit Agent DoD",
|
||||
shape=box,
|
||||
class="gpt",
|
||||
fidelity="truncate",
|
||||
prompt="Read docs/specs/coding-agent-loop-spec.md Section 9 (Definition of Done) in full. Then read every source file under crates/agent/.
|
||||
|
||||
For EACH checkbox in sections 9.1 through 9.13, evaluate whether the current Rust implementation satisfies it. Be strict.
|
||||
|
||||
Respond with ONLY a JSON object (no prose) -- don't write it out as a file:
|
||||
{
|
||||
\"spec\": \"coding-agent-loop\",
|
||||
\"model\": \"gpt-5.2\",
|
||||
\"sections\": { ... },
|
||||
\"total\": N,
|
||||
\"passed\": M,
|
||||
\"failed\": K,
|
||||
\"failed_items\": [ {\"section\": \"9.1\", \"text\": \"...\", \"reason\": \"...\"} ]
|
||||
}
|
||||
|
||||
Be thorough. Check every single checkbox."
|
||||
]
|
||||
|
||||
/*========================================================================
|
||||
* PHASE 2 — Cross-Critique (fidelity=full to see all response.* keys)
|
||||
*
|
||||
* Each model reviews the other's audit. Like megaplan's Compete phase:
|
||||
* independent work first, then adversarial review.
|
||||
*======================================================================*/
|
||||
|
||||
critique_by_gpt [
|
||||
label="GPT-5.2: Critique Opus Audits",
|
||||
shape=box,
|
||||
class="gpt",
|
||||
fidelity="full",
|
||||
prompt="You have all four audit reports available in context. The full outputs are in these context keys:
|
||||
|
||||
OPUS AUDITS:
|
||||
- response.audit_llm_opus — Opus's audit of unified-llm-spec.md Section 8
|
||||
- response.audit_agent_opus — Opus's audit of coding-agent-loop-spec.md Section 9
|
||||
|
||||
GPT AUDITS (your own):
|
||||
- response.audit_llm_gpt — your audit of unified-llm-spec.md Section 8
|
||||
- response.audit_agent_gpt — your audit of coding-agent-loop-spec.md Section 9
|
||||
|
||||
Compare them item by item. For every DoD checkbox where the two models DISAGREE (one says pass, the other says fail), re-read the relevant spec section and source file to determine who is correct.
|
||||
|
||||
Also identify items that one model flagged but the other missed entirely.
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"agreements\": { \"both_pass\": N, \"both_fail\": N },
|
||||
\"disagreements\": [
|
||||
{
|
||||
\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\",
|
||||
\"opus_says\": \"pass|fail\", \"gpt_says\": \"pass|fail\",
|
||||
\"verdict\": \"pass|fail\",
|
||||
\"reasoning\": \"...\"
|
||||
}
|
||||
],
|
||||
\"missed_by_opus\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"reason\": \"...\"} ],
|
||||
\"missed_by_gpt\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"reason\": \"...\"} ]
|
||||
}
|
||||
|
||||
Be rigorous. When in doubt, fail the checkbox — strictness prevents false confidence."
|
||||
]
|
||||
|
||||
critique_by_opus [
|
||||
label="Opus: Critique GPT-5.2 Audits",
|
||||
shape=box,
|
||||
class="opus",
|
||||
fidelity="full",
|
||||
prompt="You have all four audit reports available in context. The full outputs are in these context keys:
|
||||
|
||||
GPT AUDITS:
|
||||
- response.audit_llm_gpt — GPT-5.2's audit of unified-llm-spec.md Section 8
|
||||
- response.audit_agent_gpt — GPT-5.2's audit of coding-agent-loop-spec.md Section 9
|
||||
|
||||
OPUS AUDITS (your own):
|
||||
- response.audit_llm_opus — your audit of unified-llm-spec.md Section 8
|
||||
- response.audit_agent_opus — your audit of coding-agent-loop-spec.md Section 9
|
||||
|
||||
Compare them item by item. For every DoD checkbox where the two models DISAGREE (one says pass, the other says fail), re-read the relevant spec section and source file to determine who is correct.
|
||||
|
||||
Also identify items that one model flagged but the other missed entirely.
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"agreements\": { \"both_pass\": N, \"both_fail\": N },
|
||||
\"disagreements\": [
|
||||
{
|
||||
\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\",
|
||||
\"opus_says\": \"pass|fail\", \"gpt_says\": \"pass|fail\",
|
||||
\"verdict\": \"pass|fail\",
|
||||
\"reasoning\": \"...\"
|
||||
}
|
||||
],
|
||||
\"missed_by_opus\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"reason\": \"...\"} ],
|
||||
\"missed_by_gpt\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"reason\": \"...\"} ]
|
||||
}
|
||||
|
||||
Be rigorous. When in doubt, fail the checkbox — strictness prevents false confidence."
|
||||
]
|
||||
|
||||
/*========================================================================
|
||||
* PHASE 3 — Audit Consensus
|
||||
*
|
||||
* Merge all findings into a single agreed-upon truth.
|
||||
* Like megaplan's Merge phase: best ideas from both, disagreements resolved.
|
||||
*======================================================================*/
|
||||
|
||||
audit_consensus [
|
||||
label="Merge: Audit Consensus",
|
||||
shape=box,
|
||||
class="merge",
|
||||
fidelity="full",
|
||||
prompt="You have all prior audit and critique outputs in context. The key inputs are:
|
||||
|
||||
FOUR AUDIT REPORTS (context keys response.audit_llm_opus, response.audit_agent_opus, response.audit_llm_gpt, response.audit_agent_gpt)
|
||||
|
||||
TWO CROSS-CRITIQUES (context keys response.critique_by_gpt, response.critique_by_opus)
|
||||
|
||||
Produce a single definitive audit result. Resolution rules:
|
||||
1. If BOTH models agree a checkbox passes → pass
|
||||
2. If BOTH models agree a checkbox fails → fail
|
||||
3. If they DISAGREE, use the cross-critique verdicts. If the critiques also disagree, re-read the spec and code yourself and make the call. When in doubt, fail it.
|
||||
4. Include any items that were missed by one model but caught by the other.
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"spec_results\": {
|
||||
\"unified-llm\": { \"total\": N, \"passed\": M, \"failed\": K, \"failed_items\": [...] },
|
||||
\"coding-agent-loop\": { ... }
|
||||
},
|
||||
\"consensus_total\": N,
|
||||
\"consensus_passed\": M,
|
||||
\"consensus_failed\": K,
|
||||
\"disagreements_resolved\": N,
|
||||
\"all_failed_items\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"reason\": \"...\", \"agreed_by\": \"both|opus_only|gpt_only|resolved\"} ]
|
||||
}"
|
||||
]
|
||||
|
||||
/*========================================================================
|
||||
* PHASE 4 — Dual Triage
|
||||
*
|
||||
* Both models independently prioritize the failures, then merge.
|
||||
* Different models weight different risks differently — consensus is stronger.
|
||||
*======================================================================*/
|
||||
|
||||
triage_opus [
|
||||
label="Opus: Triage & Prioritize",
|
||||
shape=box,
|
||||
class="opus",
|
||||
fidelity="full",
|
||||
prompt="The consensus audit results are in context key response.audit_consensus. Parse the all_failed_items list from that JSON and triage every failing DoD checkbox.
|
||||
|
||||
Group failures into:
|
||||
1. IMPLEMENTABLE — can be fixed by writing/modifying Rust code (functions, handlers, logic)
|
||||
2. STRUCTURAL — requires new files, new modules, or significant architecture changes
|
||||
3. DEFERRED — requires external resources (real API keys, network access, interactive testing) that cannot be done in a code-only pass
|
||||
|
||||
For each IMPLEMENTABLE item, identify the exact file(s) to modify and briefly describe the fix. Rank them by impact (most important first).
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"model\": \"opus\",
|
||||
\"total_failing\": N,
|
||||
\"implementable\": [ {\"rank\": 1, \"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"files\": [\"...\"], \"fix\": \"...\", \"impact\": \"high|medium|low\"} ],
|
||||
\"structural\": [ ... ],
|
||||
\"deferred\": [ ... ]
|
||||
}"
|
||||
]
|
||||
|
||||
triage_gpt [
|
||||
label="GPT-5.2: Triage & Prioritize",
|
||||
shape=box,
|
||||
class="gpt",
|
||||
fidelity="full",
|
||||
prompt="The consensus audit results are in context key response.audit_consensus. Parse the all_failed_items list from that JSON and triage every failing DoD checkbox.
|
||||
|
||||
Group failures into:
|
||||
1. IMPLEMENTABLE — can be fixed by writing/modifying Rust code (functions, handlers, logic)
|
||||
2. STRUCTURAL — requires new files, new modules, or significant architecture changes
|
||||
3. DEFERRED — requires external resources (real API keys, network access, interactive testing) that cannot be done in a code-only pass
|
||||
|
||||
For each IMPLEMENTABLE item, identify the exact file(s) to modify and briefly describe the fix. Rank them by impact (most important first).
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"model\": \"gpt-5.2\",
|
||||
\"total_failing\": N,
|
||||
\"implementable\": [ {\"rank\": 1, \"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"files\": [\"...\"], \"fix\": \"...\", \"impact\": \"high|medium|low\"} ],
|
||||
\"structural\": [ ... ],
|
||||
\"deferred\": [ ... ]
|
||||
}"
|
||||
]
|
||||
|
||||
triage_merge [
|
||||
label="Merge: Triage Consensus",
|
||||
shape=box,
|
||||
class="merge",
|
||||
fidelity="full",
|
||||
prompt="You have two triage reports in context: response.triage_opus and response.triage_gpt. Merge them into a single prioritized work plan.
|
||||
|
||||
Resolution rules:
|
||||
1. If both models classify an item the same way (IMPLEMENTABLE/STRUCTURAL/DEFERRED) → keep that classification
|
||||
2. If they disagree on classification → take the MORE ACTIONABLE classification (prefer IMPLEMENTABLE over STRUCTURAL over DEFERRED)
|
||||
3. For ranking, average the ranks and re-sort. If one model identified files/fixes the other didn't, include all suggestions.
|
||||
4. Deduplicate items that both models identified.
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"total_failing\": N,
|
||||
\"implementable\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"files\": [\"...\"], \"fix\": \"...\", \"opus_rank\": N, \"gpt_rank\": N} ],
|
||||
\"structural\": [ ... ],
|
||||
\"deferred\": [ ... ],
|
||||
\"classification_disagreements\": N,
|
||||
\"verdict\": \"all_clear\" | \"has_fixes\" | \"only_deferred\"
|
||||
}
|
||||
|
||||
If total_failing == 0 or verdict == \"only_deferred\", set preferred_next_label to \"Done\".
|
||||
Otherwise set preferred_next_label to \"Fix\"."
|
||||
]
|
||||
|
||||
/*========================================================================
|
||||
* PHASE 5 — Multi-Model Implementation
|
||||
*
|
||||
* Codex implements, Opus reviews and corrects, Codex validates.
|
||||
* Like megaplan's draft→critique→merge but for code.
|
||||
*======================================================================*/
|
||||
|
||||
fix_codex [
|
||||
label="Codex: Implement Fixes",
|
||||
shape=box,
|
||||
class="codex",
|
||||
goal_gate=true,
|
||||
fidelity="full",
|
||||
prompt="The merged triage report is in context key response.triage_merge. It contains a prioritized list of IMPLEMENTABLE DoD failures.
|
||||
|
||||
Pick the top 5 most impactful items (or all if fewer than 5) and implement the fixes in Rust.
|
||||
|
||||
Begin by making sure the build is green with `cargo test`
|
||||
|
||||
For each fix:
|
||||
1. Read the relevant source file(s)
|
||||
2. Make the minimal change needed to satisfy the DoD checkbox
|
||||
3. Write the modified file(s) -- update tests as needed
|
||||
4. Verify the fix and the tests pass (`cargo test`)
|
||||
|
||||
Constraints:
|
||||
- Do NOT modify any files under docs/specs/ (those are the specs)
|
||||
- Do NOT add external dependencies beyond what's already used
|
||||
- Keep changes minimal and focused — one checkbox per fix
|
||||
- Maintain the existing code style
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"model\": \"codex\",
|
||||
\"fixes_applied\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"files_changed\": [\"...\"], \"description\": \"...\"} ],
|
||||
\"count\": N,
|
||||
\"remaining_implementable\": M
|
||||
}"
|
||||
]
|
||||
|
||||
review_fix_opus [
|
||||
label="Opus: Review & Fix",
|
||||
shape=box,
|
||||
class="opus",
|
||||
goal_gate=true,
|
||||
fidelity="full",
|
||||
prompt="Codex just implemented a batch of fixes. Its report is in context key response.fix_codex.
|
||||
|
||||
PART A — Review Codex's work:
|
||||
1. Read every file that Codex modified (check the files_changed lists in response.fix_codex)
|
||||
2. For each fix, verify it actually satisfies the DoD checkbox it claims to address
|
||||
3. Check for: correctness, edge cases, style consistency, missing error handling
|
||||
4. If a fix is wrong or incomplete, rewrite it correctly
|
||||
|
||||
PART B — Implement additional fixes:
|
||||
5. From the remaining IMPLEMENTABLE items (see response.triage_merge for the full list), pick up to 5 more and implement them
|
||||
6. Follow the same constraints as Codex (Rust, no new deps, minimal changes)
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"model\": \"opus\",
|
||||
\"codex_fixes_reviewed\": N,
|
||||
\"codex_fixes_correct\": N,
|
||||
\"codex_fixes_corrected\": [ {\"spec\": \"...\", \"section\": \"...\", \"issue\": \"...\", \"correction\": \"...\"} ],
|
||||
\"additional_fixes\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"files_changed\": [\"...\"], \"description\": \"...\"} ],
|
||||
\"total_fixes_this_round\": N,
|
||||
\"remaining_implementable\": M
|
||||
}"
|
||||
]
|
||||
|
||||
review_codex [
|
||||
label="Codex: Validate All Changes",
|
||||
shape=box,
|
||||
class="codex",
|
||||
fidelity="full",
|
||||
prompt="Opus reviewed your fixes and implemented additional ones. Its report is in context key response.review_fix_opus. Your original report is in response.fix_codex.
|
||||
|
||||
Validate the full set of changes from this round:
|
||||
1. Read every file modified in this round (check files_changed in both response.fix_codex and response.review_fix_opus)
|
||||
2. Check each change for correctness: does it satisfy its DoD checkbox?
|
||||
3. Check for regressions: did any fix break something else?
|
||||
4. Check for consistency: do all the changes work together?
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"model\": \"codex\",
|
||||
\"total_changes_reviewed\": N,
|
||||
\"all_correct\": true/false,
|
||||
\"issues_found\": [ {\"file\": \"...\", \"issue\": \"...\", \"severity\": \"critical|minor\"} ],
|
||||
\"remaining_implementable\": M
|
||||
}
|
||||
|
||||
If issues_found contains any critical items, set preferred_next_label to \"more_fixes_needed\".
|
||||
If remaining_implementable > 0 and no critical issues, set preferred_next_label to \"more_fixes_needed\".
|
||||
Otherwise set preferred_next_label to \"ready_for_build\"."
|
||||
]
|
||||
|
||||
/*========================================================================
|
||||
* PHASE 6 — Build Verification
|
||||
*======================================================================*/
|
||||
|
||||
build_check [
|
||||
label="Build & Smoke Test",
|
||||
shape=parallelogram,
|
||||
script="cargo build 2>&1 && echo '---BUILD OK---' && cargo test 2>&1 && echo '---ALL TESTS PASSED---'",
|
||||
timeout="120s"
|
||||
]
|
||||
|
||||
build_fix [
|
||||
label="Opus: Fix Build Errors",
|
||||
shape=box,
|
||||
class="opus",
|
||||
fidelity="full",
|
||||
prompt="The build or smoke tests failed. The build output is in context key command.output. Diagnose the compilation errors or test failures and fix them.
|
||||
|
||||
Read the relevant source files, identify the issue, and write corrected versions. Common issues:
|
||||
- Missing includes
|
||||
- Type mismatches
|
||||
- Undeclared functions
|
||||
|
||||
Output the fixes applied and ensure the code will compile cleanly with: cargo build"
|
||||
]
|
||||
|
||||
/*========================================================================
|
||||
* PHASE 7 — Dual Final Audit (interleaved, fidelity-isolated)
|
||||
*
|
||||
* Both models independently verify the fixes worked.
|
||||
* If either model finds a remaining failure, it counts.
|
||||
*======================================================================*/
|
||||
|
||||
final_audit_opus [
|
||||
label="Opus: Final Verification",
|
||||
shape=box,
|
||||
class="opus",
|
||||
fidelity="full",
|
||||
prompt="This is a verification pass. The items that were previously failing are listed in context key response.triage_merge (the implementable list). The fixes applied are in response.fix_codex and response.review_fix_opus.
|
||||
|
||||
Re-read both spec DoD sections:
|
||||
- docs/specs/unified-llm-spec.md Section 8
|
||||
- docs/specs/coding-agent-loop-spec.md Section 9
|
||||
|
||||
And re-read the implementation files that were changed in this iteration.
|
||||
|
||||
Check ONLY the items that were previously failing. Have they been fixed?
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"model\": \"opus\",
|
||||
\"verified_fixed\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\"} ],
|
||||
\"still_failing\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"reason\": \"...\"} ],
|
||||
\"newly_broken\": [ ... ],
|
||||
\"remaining_total\": N
|
||||
}"
|
||||
]
|
||||
|
||||
final_audit_gpt [
|
||||
label="GPT-5.2: Final Verification",
|
||||
shape=box,
|
||||
class="gpt",
|
||||
fidelity="full",
|
||||
prompt="This is a verification pass. The items that were previously failing are listed in context key response.triage_merge (the implementable list). The fixes applied are in response.fix_codex and response.review_fix_opus.
|
||||
|
||||
Re-read both spec DoD sections:
|
||||
- docs/specs/unified-llm-spec.md Section 8
|
||||
- docs/specs/coding-agent-loop-spec.md Section 9
|
||||
|
||||
And re-read the implementation files that were changed in this iteration.
|
||||
|
||||
Check ONLY the items that were previously failing. Have they been fixed?
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"model\": \"gpt-5.2\",
|
||||
\"verified_fixed\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\"} ],
|
||||
\"still_failing\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"reason\": \"...\"} ],
|
||||
\"newly_broken\": [ ... ],
|
||||
\"remaining_total\": N
|
||||
}"
|
||||
]
|
||||
|
||||
final_consensus [
|
||||
label="Merge: Final Consensus",
|
||||
shape=box,
|
||||
class="merge",
|
||||
fidelity="full",
|
||||
prompt="You have final audit results from both models in context: response.final_audit_opus and response.final_audit_gpt. Merge them into a definitive status.
|
||||
|
||||
Rules:
|
||||
1. An item is only \"verified_fixed\" if BOTH models agree it's fixed
|
||||
2. If EITHER model says an item is still failing, it counts as still failing
|
||||
3. Union all newly_broken items from both models
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"verified_fixed\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"agreed_by\": \"both|opus_only|gpt_only\"} ],
|
||||
\"still_failing\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"flagged_by\": \"both|opus_only|gpt_only\", \"reason\": \"...\"} ],
|
||||
\"newly_broken\": [ ... ],
|
||||
\"remaining_total\": N
|
||||
}
|
||||
|
||||
If remaining_total == 0 (ignoring DEFERRED items), set preferred_next_label to \"Complete\".
|
||||
Otherwise set preferred_next_label to \"more_work_needed\"."
|
||||
]
|
||||
|
||||
/*========================================================================
|
||||
* PHASE 8 — Human Gate
|
||||
*======================================================================*/
|
||||
|
||||
review_gate [
|
||||
label="A) Accept & finish\nB) Push for another round",
|
||||
shape=hexagon
|
||||
]
|
||||
|
||||
/*========================================================================
|
||||
* EDGES — Serial interleaved chain
|
||||
*
|
||||
* The engine is single-path, so we interleave model audits per-spec.
|
||||
* fidelity="truncate" on audit nodes prevents cross-model anchoring.
|
||||
*======================================================================*/
|
||||
|
||||
/* Phase 1: Interleaved audits (Opus then GPT for each spec) */
|
||||
start -> audit_llm_opus
|
||||
audit_llm_opus -> audit_llm_gpt
|
||||
audit_llm_gpt -> audit_agent_opus
|
||||
audit_agent_opus -> audit_agent_gpt
|
||||
|
||||
/* Phase 2: Cross-critique (now sequential — GPT critiques Opus, then Opus critiques GPT) */
|
||||
audit_agent_gpt -> critique_by_gpt
|
||||
critique_by_gpt -> critique_by_opus
|
||||
|
||||
/* Phase 3: Consensus */
|
||||
critique_by_opus -> audit_consensus
|
||||
|
||||
/* Phase 4: Dual triage (sequential — Opus then GPT then merge) */
|
||||
audit_consensus -> triage_opus
|
||||
triage_opus -> triage_gpt
|
||||
triage_gpt -> triage_merge
|
||||
|
||||
/* Triage decision */
|
||||
triage_merge -> exit [label="Done", condition="preferred_label=Done"]
|
||||
triage_merge -> fix_codex [label="Fix", condition="preferred_label=Fix", weight=10]
|
||||
triage_merge -> exit [label="Only deferred remain"]
|
||||
|
||||
/* Phase 5: Multi-model implementation (sequential alternation) */
|
||||
fix_codex -> review_fix_opus
|
||||
review_fix_opus -> review_codex
|
||||
|
||||
/* Implementation loop */
|
||||
review_codex -> fix_codex [label="More fixes needed", condition="preferred_label=more_fixes_needed", loop_restart=true]
|
||||
review_codex -> build_check [label="Ready for build", condition="preferred_label=ready_for_build"]
|
||||
review_codex -> fix_codex [label="Fallback"]
|
||||
|
||||
/* Phase 6: Build */
|
||||
build_check -> final_audit_opus [label="Build OK", condition="outcome=success"]
|
||||
build_check -> build_fix [label="Build failed"]
|
||||
build_fix -> build_check
|
||||
|
||||
/* Phase 7: Dual final audit (sequential — Opus then GPT then consensus) */
|
||||
final_audit_opus -> final_audit_gpt
|
||||
final_audit_gpt -> final_consensus
|
||||
|
||||
/* Final decision */
|
||||
final_consensus -> review_gate [label="Complete", condition="preferred_label=Complete"]
|
||||
final_consensus -> triage_merge [label="More work needed"]
|
||||
|
||||
/* Phase 8: Human gate */
|
||||
review_gate -> exit [label="A) Accept"]
|
||||
review_gate -> triage_merge [label="B) Another round"]
|
||||
}
|
||||
231
test/docs/examples/definition-of-done/spec-dod.dot
Normal file
231
test/docs/examples/definition-of-done/spec-dod.dot
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
digraph SpecDoD {
|
||||
graph [
|
||||
goal="Satisfy every Definition of Done checkbox across both specs (unified-llm-spec.md, coding-agent-loop-spec.md). The implementation is in Rust under crates/. Do NOT modify the spec files. Only modify implementation code.",
|
||||
default_max_retry="3",
|
||||
retry_target="triage",
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-opus-4-6; llm_provider: anthropic; }
|
||||
.audit { reasoning_effort: high; }
|
||||
.fix { llm_model: claude-opus-4-6; reasoning_effort: high; }
|
||||
#final_audit { reasoning_effort: high; }
|
||||
"
|
||||
]
|
||||
|
||||
start [shape=Mdiamond]
|
||||
exit [shape=Msquare]
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
* Phase 1: Baseline audit — read every DoD checkbox, check the code
|
||||
*----------------------------------------------------------------------*/
|
||||
|
||||
audit_llm [
|
||||
label="Audit: Unified LLM Client DoD",
|
||||
shape=box,
|
||||
class="audit",
|
||||
prompt="Read docs/specs/unified-llm-spec.md Section 8 (Definition of Done) in full. Then read every source file under crates/llm/src/.
|
||||
|
||||
For EACH checkbox in sections 8.1 through 8.10, evaluate whether the current Rust implementation satisfies it. Be strict — a checkbox is only checked if the feature is fully implemented and would work correctly at runtime.
|
||||
|
||||
Respond with ONLY a JSON object (no prose) -- don't write it out as a file:
|
||||
{
|
||||
\"spec\": \"unified-llm\",
|
||||
\"sections\": {
|
||||
\"8.1\": { \"title\": \"Core Infrastructure\", \"items\": [ {\"text\": \"...\", \"pass\": true/false, \"reason\": \"...\"} ] },
|
||||
...
|
||||
},
|
||||
\"total\": N,
|
||||
\"passed\": M,
|
||||
\"failed\": K,
|
||||
\"failed_items\": [ {\"section\": \"8.2\", \"text\": \"...\", \"reason\": \"...\"} ]
|
||||
}
|
||||
|
||||
Be thorough. Check every single checkbox."
|
||||
]
|
||||
|
||||
audit_agent [
|
||||
label="Audit: Coding Agent Loop DoD",
|
||||
shape=box,
|
||||
class="audit",
|
||||
prompt="Read docs/specs/coding-agent-loop-spec.md Section 9 (Definition of Done) in full. Then read every source file under crates/agent/.
|
||||
|
||||
For EACH checkbox in sections 9.1 through 9.13, evaluate whether the current Rust implementation satisfies it. Be strict.
|
||||
|
||||
Respond with ONLY a JSON object (no prose) -- don't write it out as a file:
|
||||
{
|
||||
\"spec\": \"coding-agent-loop\",
|
||||
\"sections\": { ... },
|
||||
\"total\": N,
|
||||
\"passed\": M,
|
||||
\"failed\": K,
|
||||
\"failed_items\": [ {\"section\": \"9.1\", \"text\": \"...\", \"reason\": \"...\"} ]
|
||||
}
|
||||
|
||||
Be thorough. Check every single checkbox."
|
||||
]
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
* Phase 2: Triage — merge results, prioritize failures, decide next step
|
||||
*----------------------------------------------------------------------*/
|
||||
|
||||
triage [
|
||||
label="Triage & Prioritize",
|
||||
shape=box,
|
||||
prompt="You have two audit reports in context (from audit_llm, audit_agent). Merge them into a single prioritized list of ALL failing DoD checkboxes.
|
||||
|
||||
Group failures into:
|
||||
1. IMPLEMENTABLE — can be fixed by writing/modifying Rust code (functions, handlers, logic)
|
||||
2. STRUCTURAL — requires new files, new modules, or significant architecture changes
|
||||
3. DEFERRED — requires external resources (real API keys, network access, interactive testing) that cannot be done in a code-only pass
|
||||
|
||||
For each IMPLEMENTABLE item, identify the exact file(s) to modify and briefly describe the fix.
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"total_failing\": N,
|
||||
\"implementable\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"files\": [\"...\"], \"fix\": \"...\"} ],
|
||||
\"structural\": [ ... ],
|
||||
\"deferred\": [ ... ],
|
||||
\"verdict\": \"all_clear\" | \"has_fixes\" | \"only_deferred\"
|
||||
}
|
||||
|
||||
If total_failing == 0 or verdict == \"only_deferred\", set preferred_next_label to \"Done\".
|
||||
Otherwise set preferred_next_label to \"Fix\"."
|
||||
]
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
* Phase 3: Fix — implement the highest-priority fixes
|
||||
*----------------------------------------------------------------------*/
|
||||
|
||||
fix_batch [
|
||||
label="Implement Fixes",
|
||||
shape=box,
|
||||
class="fix",
|
||||
goal_gate=true,
|
||||
prompt="The triage report identified IMPLEMENTABLE DoD failures. Pick the top 5 most impactful items (or all if fewer than 5) and implement the fixes in Rust.
|
||||
|
||||
Begin by making sure the build is green with `cargo test`
|
||||
|
||||
For each fix:
|
||||
1. Read the relevant source file(s)
|
||||
2. Make the minimal change needed to satisfy the DoD checkbox
|
||||
3. Write the modified file(s) -- update tests as needed
|
||||
4. Verify the fix and the tests pass (`cargo test`)
|
||||
|
||||
Constraints:
|
||||
- Do NOT modify any files under docs/specs/ (those are the specs)
|
||||
- Do NOT add external dependencies beyond what's already used
|
||||
- Keep changes minimal and focused — one checkbox per fix
|
||||
- Maintain the existing code style
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"fixes_applied\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"files_changed\": [\"...\"], \"description\": \"...\"} ],
|
||||
\"count\": N,
|
||||
\"remaining_implementable\": M
|
||||
}
|
||||
|
||||
If remaining_implementable > 0, set preferred_next_label to \"more_fixes_needed\".
|
||||
Otherwise set preferred_next_label to \"Re-audit\"."
|
||||
]
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
* Phase 4: Build verification
|
||||
*----------------------------------------------------------------------*/
|
||||
|
||||
build_check [
|
||||
label="Build & Smoke Test",
|
||||
shape=parallelogram,
|
||||
script="cargo build 2>&1 && echo '---BUILD OK---' && cargo test 2>&1 && echo '---ALL TESTS PASSED---'",
|
||||
timeout="120s"
|
||||
]
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
* Phase 5: Build failure recovery
|
||||
*----------------------------------------------------------------------*/
|
||||
|
||||
build_fix [
|
||||
label="Fix Build Errors",
|
||||
shape=box,
|
||||
class="fix",
|
||||
prompt="The build or smoke tests failed. Read the build output from context (command.output key). Diagnose the compilation errors or test failures and fix them.
|
||||
|
||||
Read the relevant source files, identify the issue, and write corrected versions. Common issues:
|
||||
- Missing includes
|
||||
- Type mismatches
|
||||
- Undeclared functions
|
||||
|
||||
Output the fixes applied and ensure the code will compile cleanly with: cargo build"
|
||||
]
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
* Phase 6: Final audit to confirm fixes worked
|
||||
*----------------------------------------------------------------------*/
|
||||
|
||||
final_audit [
|
||||
label="Final Verification Audit",
|
||||
shape=box,
|
||||
prompt="This is a verification pass. Re-read both spec DoD sections:
|
||||
- docs/specs/unified-llm-spec.md Section 8
|
||||
- docs/specs/coding-agent-loop-spec.md Section 9
|
||||
|
||||
And re-read the implementation files that were changed in this iteration.
|
||||
|
||||
Check ONLY the items that were previously failing. Have they been fixed?
|
||||
|
||||
Respond with JSON (not by writing out a file):
|
||||
{
|
||||
\"verified_fixed\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\"} ],
|
||||
\"still_failing\": [ {\"spec\": \"...\", \"section\": \"...\", \"text\": \"...\", \"reason\": \"...\"} ],
|
||||
\"newly_broken\": [ ... ],
|
||||
\"remaining_total\": N
|
||||
}
|
||||
|
||||
If remaining_total == 0 (ignoring DEFERRED items), set preferred_next_label to \"Complete\".
|
||||
Otherwise set preferred_next_label to \"more_work_needed\"."
|
||||
]
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
* Phase 7: Human gate — confirm completion or push for another round
|
||||
*----------------------------------------------------------------------*/
|
||||
|
||||
review_gate [
|
||||
label="A) Accept & finish\nB) Push for another round",
|
||||
shape=hexagon
|
||||
]
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
* Edges
|
||||
*----------------------------------------------------------------------*/
|
||||
|
||||
start -> audit_llm
|
||||
|
||||
/* Sequential audit chain */
|
||||
audit_llm -> audit_agent
|
||||
audit_agent -> triage
|
||||
|
||||
/* Triage decision */
|
||||
triage -> exit [label="Done", condition="preferred_label=Done"]
|
||||
triage -> fix_batch [label="Fix", condition="preferred_label=Fix", weight=10]
|
||||
triage -> exit [label="Only deferred remain"]
|
||||
|
||||
/* Fix -> build check */
|
||||
fix_batch -> build_check
|
||||
|
||||
/* Build check outcomes */
|
||||
build_check -> final_audit [label="Build OK", condition="outcome=success"]
|
||||
build_check -> build_fix [label="Build failed"]
|
||||
|
||||
/* Build fix loops back to build check */
|
||||
build_fix -> build_check
|
||||
|
||||
/* Fix batch can loop for more fixes */
|
||||
fix_batch -> fix_batch [label="More fixes needed", condition="preferred_label=more_fixes_needed", loop_restart=true]
|
||||
|
||||
/* Final audit outcomes */
|
||||
final_audit -> review_gate [label="Complete", condition="preferred_label=Complete"]
|
||||
final_audit -> triage [label="More work needed"]
|
||||
|
||||
/* Human review gate */
|
||||
review_gate -> exit [label="A) Accept"]
|
||||
review_gate -> triage [label="B) Another round"]
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
digraph NLSpecConformance {
|
||||
graph [
|
||||
goal="Implement a conformant system from a natural language specification",
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-haiku-4-5; llm_provider: anthropic; }
|
||||
.impl { llm_model: claude-sonnet-4-5; reasoning_effort: high; }
|
||||
"
|
||||
]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
// Phase 1: Read spec and plan
|
||||
plan [label="Plan", class="impl", prompt="@prompts/plan.md"]
|
||||
|
||||
// Phase 2: Build the initial implementation
|
||||
subgraph cluster_impl {
|
||||
label = "Implement & Conform"
|
||||
node [thread_id="impl", fidelity="full"]
|
||||
|
||||
implement [label="Implement", class="impl", prompt="@prompts/implement.md"]
|
||||
fix [label="Fix Failures", class="impl", prompt="@prompts/fix.md", max_visits=5]
|
||||
}
|
||||
|
||||
// Phase 3: Quick conformance loop
|
||||
test_quick [label="Quick Conformance", shape=parallelogram, script="make conformance-quick 2>&1 || true"]
|
||||
gate_quick [shape=diamond, label="Quick suite passing?"]
|
||||
|
||||
// Phase 4: Full conformance
|
||||
test_full [label="Full Conformance", shape=parallelogram, script="make conformance-full 2>&1 || true", goal_gate=true]
|
||||
gate_full [shape=diamond, label="All tests passing?"]
|
||||
|
||||
// Wiring
|
||||
start -> plan -> implement -> test_quick -> gate_quick
|
||||
|
||||
gate_quick -> test_full [label="Pass", condition="outcome=success"]
|
||||
gate_quick -> fix [label="Fix"]
|
||||
|
||||
fix -> test_quick
|
||||
|
||||
test_full -> gate_full
|
||||
|
||||
gate_full -> exit [label="Pass", condition="outcome=success"]
|
||||
gate_full -> fix [label="Fix"]
|
||||
}
|
||||
1
test/docs/examples/nlspec-conformance/prompts/fix.md
Normal file
1
test/docs/examples/nlspec-conformance/prompts/fix.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Stub prompt for testing.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Stub prompt for testing.
|
||||
1
test/docs/examples/nlspec-conformance/prompts/plan.md
Normal file
1
test/docs/examples/nlspec-conformance/prompts/plan.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Stub prompt for testing.
|
||||
122
test/docs/examples/semantic-port/semantic-port.dot
Normal file
122
test/docs/examples/semantic-port/semantic-port.dot
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
digraph SemanticPort {
|
||||
graph [
|
||||
goal="Port semantic changes from upstream Python repository to our Go implementation",
|
||||
rankdir=LR,
|
||||
default_max_retry=3,
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-sonnet-4-5; llm_provider: anthropic; }
|
||||
.hard { llm_model: claude-opus-4-6; llm_provider: anthropic; }
|
||||
.analyze { llm_model: gemini-3.1-pro-preview; llm_provider: gemini; }
|
||||
"
|
||||
]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
// Phase 1: Find the next unprocessed commit
|
||||
fetch [
|
||||
label="Fetch & Identify",
|
||||
prompt="Find the next unprocessed upstream commit.\n\n\
|
||||
1. Run `python3 ledger/manage.py earliest` to get the oldest commit with status=new\n\
|
||||
2. If found, write the commit details to .arc/current_commit.md and respond with:\n\
|
||||
{\"preferred_next_label\": \"process\"}\n\
|
||||
3. If no new commits exist:\n\
|
||||
a. Fetch latest from upstream: cd upstream/ && git fetch && git pull\n\
|
||||
b. Find commits newer than the latest in ledger.tsv\n\
|
||||
c. Add them with `python3 ledger/manage.py add <sha> <timestamp>`\n\
|
||||
d. Try `earliest` again\n\
|
||||
e. If still none, respond with: {\"preferred_next_label\": \"done\"}\n\n\
|
||||
Respond with exactly one of: process or done."
|
||||
]
|
||||
|
||||
// Phase 2: Analyze the commit and decide port vs. skip
|
||||
analyze [
|
||||
label="Analyze & Decide",
|
||||
class="analyze",
|
||||
prompt="Read .arc/current_commit.md for the commit to process.\n\
|
||||
Examine it with `git show <sha>` in the upstream/ directory.\n\n\
|
||||
Analyze the semantic changes — what functionality changed, not just syntax.\n\
|
||||
Decide if this change is relevant to our Go implementation or if it is\n\
|
||||
Python-specific, docs-only, or not applicable.\n\n\
|
||||
Write .arc/analysis.md with sections:\n\
|
||||
- Commit summary\n\
|
||||
- Semantic analysis\n\
|
||||
- Decision: PORT or ACKNOWLEDGE (with reasoning)\n\
|
||||
- Port plan (if porting): concrete tasks with file:line references\n\n\
|
||||
If decision is ACKNOWLEDGE:\n\
|
||||
1. Update ledger: `python3 ledger/manage.py update <sha> acknowledged`\n\
|
||||
2. Commit: `git add ledger/ && git commit -m \"semport: acknowledge <sha> - <reason>\"`\n\
|
||||
3. Respond with: {\"preferred_next_label\": \"skip\"}\n\n\
|
||||
If decision is PORT:\n\
|
||||
Respond with: {\"preferred_next_label\": \"port\"}"
|
||||
]
|
||||
|
||||
// Phase 3: Refine the plan
|
||||
plan [
|
||||
label="Finalize Plan",
|
||||
prompt="Read .arc/analysis.md. Perform a final editorial pass.\n\
|
||||
Write .arc/plan.md ensuring each task has:\n\
|
||||
- Concrete file:line references in our Go code\n\
|
||||
- Clear acceptance criteria\n\
|
||||
- Directly executable instructions\n\n\
|
||||
Remove vague language. The plan must be actionable."
|
||||
]
|
||||
|
||||
// Phase 4: Implement the port
|
||||
implement [
|
||||
label="Implement Port",
|
||||
class="hard",
|
||||
prompt="Follow the plan in .arc/plan.md.\n\
|
||||
Port the semantic changes to the Go codebase.\n\
|
||||
Focus on semantic equivalence, not literal translation.\n\
|
||||
Use Go idioms and respect existing architecture.\n\
|
||||
Log all changes to .arc/implementation_log.md."
|
||||
]
|
||||
|
||||
// Phase 5: Validate
|
||||
validate [
|
||||
label="Validate",
|
||||
shape=parallelogram,
|
||||
script="cd go-sdk && go build ./... && go test ./... -v 2>&1 || true"
|
||||
]
|
||||
|
||||
gate [shape=diamond, label="Tests pass?"]
|
||||
|
||||
// Phase 6: Fix failures
|
||||
fix [
|
||||
label="Analyze & Fix",
|
||||
class="hard",
|
||||
max_visits=3,
|
||||
prompt="Tests or build failed. Read the test output from the prior stage.\n\
|
||||
Read .arc/plan.md and .arc/implementation_log.md.\n\
|
||||
Diagnose the root cause, fix the issue, and log the fix."
|
||||
]
|
||||
|
||||
// Phase 7: Update ledger and commit
|
||||
finalize [
|
||||
label="Finalize",
|
||||
prompt="All tests pass. Finalize this port:\n\
|
||||
1. Update ledger: `python3 ledger/manage.py update <sha> implemented`\n\
|
||||
2. Commit all changes:\n\
|
||||
`git add -A && git commit -m \"semport: implement <sha> - <description>\"`\n\
|
||||
3. Write a brief summary to .arc/implementation_summary.md"
|
||||
]
|
||||
|
||||
// Wiring
|
||||
start -> fetch
|
||||
|
||||
fetch -> analyze [label="Process", condition="preferred_label=process"]
|
||||
fetch -> exit [label="Done"]
|
||||
|
||||
analyze -> plan [label="Port", condition="preferred_label=port"]
|
||||
analyze -> fetch [label="Skip"]
|
||||
|
||||
plan -> implement -> validate -> gate
|
||||
|
||||
gate -> finalize [label="Pass", condition="outcome=success"]
|
||||
gate -> fix [label="Fail"]
|
||||
|
||||
fix -> validate
|
||||
|
||||
finalize -> fetch
|
||||
}
|
||||
170
test/docs/examples/solitaire/build-solitaire.dot
Normal file
170
test/docs/examples/solitaire/build-solitaire.dot
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
digraph BuildSolitaire {
|
||||
graph [
|
||||
goal="Build a terminal-based solitaire (Klondike) game in Python",
|
||||
rankdir=LR,
|
||||
default_max_retry=3,
|
||||
retry_target="impl_setup",
|
||||
fallback_retry_target="impl_game_logic",
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-sonnet-4-5; llm_provider: anthropic; }
|
||||
.hard { llm_model: claude-opus-4-6; llm_provider: anthropic; }
|
||||
.verify { llm_model: claude-haiku-4-5; llm_provider: anthropic; }
|
||||
"
|
||||
]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
// Phase 0: Expand the goal into a detailed spec
|
||||
expand_spec [
|
||||
label="Expand Spec",
|
||||
prompt="Expand the goal into a detailed spec covering:\n\
|
||||
- Game rules and data structures (Card, Deck, Pile types)\n\
|
||||
- Terminal rendering approach (curses library)\n\
|
||||
- Input handling and move validation\n\
|
||||
- Win/loss detection\n\
|
||||
- UI layout\n\
|
||||
- Test strategy\n\n\
|
||||
Write the spec to spec.md."
|
||||
]
|
||||
|
||||
// Phase 1: Project setup
|
||||
impl_setup [
|
||||
label="Setup Project",
|
||||
prompt="Read spec.md. Create the Python project structure:\n\
|
||||
pyproject.toml, src/ directory, tests/ directory, main.py stub.\n\
|
||||
Run: python3 -m py_compile src/*.py"
|
||||
]
|
||||
|
||||
verify_setup [label="Verify Setup", class="verify",
|
||||
prompt="Verify project setup: check pyproject.toml exists,\n\
|
||||
source directories exist, and files compile without errors.\n\
|
||||
Run: python3 -m py_compile src/*.py"
|
||||
]
|
||||
|
||||
check_setup [shape=diamond, label="Setup OK?"]
|
||||
|
||||
// Phase 2: Core data structures
|
||||
impl_data [
|
||||
label="Data Structures",
|
||||
prompt="Read spec.md. Implement Card, Deck, and Pile types\n\
|
||||
with unit tests. Run: python3 -m pytest tests/ -v"
|
||||
]
|
||||
|
||||
verify_data [label="Verify Data", class="verify",
|
||||
prompt="Verify data structures: build, run tests, check that\n\
|
||||
Card, Deck, and Pile types are defined and basic operations work.\n\
|
||||
Run: python3 -m pytest tests/ -v"
|
||||
]
|
||||
|
||||
check_data [shape=diamond, label="Data OK?"]
|
||||
|
||||
// Phase 3: Game logic (hardest phase)
|
||||
impl_logic [
|
||||
label="Game Logic",
|
||||
class="hard",
|
||||
max_retries=2,
|
||||
prompt="Read spec.md and the data structure files.\n\
|
||||
Implement Klondike rules: initial deal, move validation,\n\
|
||||
auto-complete detection, win condition, undo.\n\
|
||||
Write tests for legal/illegal moves, win detection, edge cases.\n\
|
||||
Run: python3 -m pytest tests/ -v"
|
||||
]
|
||||
|
||||
verify_logic [label="Verify Logic", class="verify",
|
||||
prompt="Verify game logic: run all tests, check move validation,\n\
|
||||
win detection, and undo.\n\
|
||||
Run: python3 -m pytest tests/ -v"
|
||||
]
|
||||
|
||||
check_logic [shape=diamond, label="Logic OK?"]
|
||||
|
||||
// Phase 4: Terminal UI
|
||||
impl_ui [
|
||||
label="Terminal UI",
|
||||
class="hard",
|
||||
max_retries=2,
|
||||
prompt="Read spec.md and game logic files.\n\
|
||||
Implement terminal UI with curses: card rendering (ASCII art),\n\
|
||||
board layout, keyboard input, move selection, help text.\n\
|
||||
Run: python3 -m pytest tests/ && python3 -m py_compile src/*.py"
|
||||
]
|
||||
|
||||
verify_ui [label="Verify UI", class="verify",
|
||||
prompt="Verify terminal UI: build, run tests, check that\n\
|
||||
renderer and input handler exist, game can be instantiated.\n\
|
||||
Run: python3 -m pytest tests/"
|
||||
]
|
||||
|
||||
check_ui [shape=diamond, label="UI OK?"]
|
||||
|
||||
// Phase 5: Integration
|
||||
impl_integration [
|
||||
label="Integrate",
|
||||
prompt="Wire up main.py to start the game loop.\n\
|
||||
Connect UI input to game logic. Add game over screen,\n\
|
||||
help menu, and README with build/run instructions.\n\
|
||||
Run: python3 -m pytest tests/"
|
||||
]
|
||||
|
||||
verify_integration [label="Verify Integration", class="verify",
|
||||
prompt="Verify integration: build, run all tests, check README\n\
|
||||
exists, verify the game starts without errors.\n\
|
||||
Run: python3 -m pytest tests/"
|
||||
]
|
||||
|
||||
check_integration [shape=diamond, label="Integration OK?"]
|
||||
|
||||
// Phase 6: Final review (goal gate)
|
||||
review [
|
||||
label="Final Review",
|
||||
class="hard",
|
||||
goal_gate=true,
|
||||
prompt="Read spec.md in full. Review the complete implementation:\n\
|
||||
- All Klondike rules correctly implemented\n\
|
||||
- Terminal UI works and is intuitive\n\
|
||||
- Tests comprehensive and passing\n\
|
||||
- README clear and accurate\n\n\
|
||||
Run the full test suite. Write a review to review.md.\n\
|
||||
Run: python3 -m pytest tests/ -v"
|
||||
]
|
||||
|
||||
check_review [shape=diamond, label="Review OK?"]
|
||||
|
||||
// Wiring: linear phases with verify-gate loops
|
||||
start -> expand_spec -> impl_setup -> verify_setup -> check_setup
|
||||
|
||||
check_setup -> impl_data [condition="outcome=success"]
|
||||
check_setup -> impl_setup [condition="outcome=fail", label="Retry"]
|
||||
check_setup -> impl_setup
|
||||
|
||||
impl_data -> verify_data -> check_data
|
||||
|
||||
check_data -> impl_logic [condition="outcome=success"]
|
||||
check_data -> impl_data [condition="outcome=fail", label="Retry"]
|
||||
check_data -> impl_data
|
||||
|
||||
impl_logic -> verify_logic -> check_logic
|
||||
|
||||
check_logic -> impl_ui [condition="outcome=success"]
|
||||
check_logic -> impl_logic [condition="outcome=fail", label="Retry"]
|
||||
check_logic -> impl_logic
|
||||
|
||||
impl_ui -> verify_ui -> check_ui
|
||||
|
||||
check_ui -> impl_integration [condition="outcome=success"]
|
||||
check_ui -> impl_ui [condition="outcome=fail", label="Retry"]
|
||||
check_ui -> impl_ui
|
||||
|
||||
impl_integration -> verify_integration -> check_integration
|
||||
|
||||
check_integration -> review [condition="outcome=success"]
|
||||
check_integration -> impl_integration [condition="outcome=fail", label="Retry"]
|
||||
check_integration -> impl_integration
|
||||
|
||||
review -> check_review
|
||||
|
||||
check_review -> exit [condition="outcome=success"]
|
||||
check_review -> impl_ui [condition="outcome=fail", label="Fix"]
|
||||
check_review -> impl_ui
|
||||
}
|
||||
10
test/docs/execution/context/example.dot
Normal file
10
test/docs/execution/context/example.dot
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
digraph Example {
|
||||
graph [goal="Test default fidelity setting", default_fidelity="summary:medium"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
plan [label="Plan", prompt="Create a plan."]
|
||||
|
||||
start -> plan -> exit
|
||||
}
|
||||
11
test/docs/execution/failures/example-02.dot
Normal file
11
test/docs/execution/failures/example-02.dot
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
digraph Example {
|
||||
graph [goal="Test max_node_visits with per-node max_visits", max_node_visits="20"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
implement [label="Implement", prompt="Implement the feature."]
|
||||
fix [label="Fix", max_visits=3, prompt="Fix the issues."]
|
||||
|
||||
start -> implement -> fix -> exit
|
||||
}
|
||||
12
test/docs/execution/failures/example-03.dot
Normal file
12
test/docs/execution/failures/example-03.dot
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
digraph Example {
|
||||
graph [goal="Test retry_target attributes", retry_target="plan"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
plan [label="Plan", prompt="Create a plan."]
|
||||
implement [label="Implement", prompt="Implement the plan."]
|
||||
verify [label="Verify", goal_gate="true", retry_target="implement", prompt="Verify the implementation."]
|
||||
|
||||
start -> plan -> implement -> verify -> exit
|
||||
}
|
||||
10
test/docs/execution/failures/example-04.dot
Normal file
10
test/docs/execution/failures/example-04.dot
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
digraph Example {
|
||||
graph [goal="Test stall_timeout setting", stall_timeout="300"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
plan [label="Plan", prompt="Create a plan."]
|
||||
|
||||
start -> plan -> exit
|
||||
}
|
||||
10
test/docs/execution/failures/example.dot
Normal file
10
test/docs/execution/failures/example.dot
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
digraph Example {
|
||||
graph [goal="Test max_node_visits graph setting", max_node_visits="20"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
implement [label="Implement", prompt="Implement the feature."]
|
||||
|
||||
start -> implement -> exit
|
||||
}
|
||||
23
test/docs/execution/interviews/default-choice.dot
Normal file
23
test/docs/execution/interviews/default-choice.dot
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// Assembled from docs/execution/interviews.mdx snippet
|
||||
// Tests human gate with default_choice attribute
|
||||
|
||||
digraph DefaultChoice {
|
||||
graph [goal="Exercise human gate with default choice from the interviews docs page"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
deploy [label="Deploy", prompt="Deploy the changes."]
|
||||
abort [label="Abort", prompt="Abort the deployment."]
|
||||
|
||||
// Line 114: Human gate with human.default_choice
|
||||
approve [shape=hexagon, label="Approve?", human.default_choice="deploy"]
|
||||
|
||||
start -> approve
|
||||
|
||||
approve -> deploy [label="[A] Deploy"]
|
||||
approve -> abort [label="[R] Abort"]
|
||||
|
||||
deploy -> exit
|
||||
abort -> exit
|
||||
}
|
||||
11
test/docs/execution/run-configuration/c-i.dot
Normal file
11
test/docs/execution/run-configuration/c-i.dot
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
digraph CI {
|
||||
graph [goal="Run tests for $repo_name"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
clone [shape=parallelogram, script="git clone $repo_url repo"]
|
||||
test [label="Test", prompt="Run the $language test suite."]
|
||||
|
||||
start -> clone -> test -> exit
|
||||
}
|
||||
8
test/docs/execution/run-configuration/run-c-i.toml
Normal file
8
test/docs/execution/run-configuration/run-c-i.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
version = 1
|
||||
goal = "Run tests for $repo_name"
|
||||
graph = "c-i.dot"
|
||||
|
||||
[vars]
|
||||
language = "test-language"
|
||||
repo_name = "test-repo_name"
|
||||
repo_url = "test-repo_url"
|
||||
182
test/docs/extract_dots.py
Normal file
182
test/docs/extract_dots.py
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Extract full digraph DOT examples from Arc documentation files."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
DOCS_DIR = Path(__file__).resolve().parent.parent.parent / "docs"
|
||||
OUTPUT_DIR = Path(__file__).resolve().parent
|
||||
|
||||
|
||||
def extract_dot_blocks(filepath: Path) -> list[dict]:
|
||||
"""Extract all ```dot code blocks from a file."""
|
||||
blocks = []
|
||||
with open(filepath) as f:
|
||||
lines = f.readlines()
|
||||
|
||||
in_dot = False
|
||||
block_start = 0
|
||||
block_lines: list[str] = []
|
||||
title = ""
|
||||
|
||||
for i, line in enumerate(lines, 1):
|
||||
m = re.match(r'\s*```dot(?:\s+title="([^"]*)")?\s*$', line)
|
||||
if m and not in_dot:
|
||||
in_dot = True
|
||||
block_start = i
|
||||
block_lines = []
|
||||
title = m.group(1) or ""
|
||||
elif in_dot and re.match(r"\s*```\s*$", line):
|
||||
in_dot = False
|
||||
code = "".join(block_lines)
|
||||
is_full = "digraph" in code
|
||||
blocks.append(
|
||||
{
|
||||
"line": block_start,
|
||||
"code": code,
|
||||
"is_full": is_full,
|
||||
"title": title,
|
||||
"num_lines": len(block_lines),
|
||||
}
|
||||
)
|
||||
elif in_dot:
|
||||
block_lines.append(line)
|
||||
|
||||
return blocks
|
||||
|
||||
|
||||
def page_dir(filepath: Path) -> Path:
|
||||
"""Convert docs/tutorials/hello-world.mdx -> tutorials/hello-world/"""
|
||||
rel = filepath.relative_to(DOCS_DIR)
|
||||
return Path(rel.parent) / rel.stem
|
||||
|
||||
|
||||
def derive_filename(block: dict, index: int) -> str:
|
||||
"""Derive .dot filename from title or digraph name."""
|
||||
if block["title"]:
|
||||
name = block["title"]
|
||||
if not name.endswith(".dot"):
|
||||
name += ".dot"
|
||||
return name
|
||||
|
||||
# Extract digraph name
|
||||
m = re.search(r"digraph\s+(\w+)", block["code"])
|
||||
if m:
|
||||
# Convert CamelCase to kebab-case
|
||||
name = re.sub(r"(?<!^)(?=[A-Z])", "-", m.group(1)).lower()
|
||||
return f"{name}.dot"
|
||||
|
||||
return f"workflow-{index:02d}.dot"
|
||||
|
||||
|
||||
def find_prompt_refs(code: str) -> list[str]:
|
||||
"""Find @path/to/file.md references in DOT code."""
|
||||
return re.findall(r'@([\w./-]+\.md)', code)
|
||||
|
||||
|
||||
def find_custom_vars(code: str) -> list[str]:
|
||||
"""Find $variable references that aren't $goal or $$-escaped."""
|
||||
# Remove $$ escapes first
|
||||
cleaned = code.replace("$$", "")
|
||||
vars_found = set(re.findall(r'\$([a-zA-Z_]\w*)', cleaned))
|
||||
vars_found.discard("goal")
|
||||
return sorted(vars_found)
|
||||
|
||||
|
||||
def main():
|
||||
skip_pages = {"changelog/2026-02-27"} # deprecated syntax
|
||||
|
||||
extracted = 0
|
||||
skipped_snippets = 0
|
||||
prompt_stubs_needed: list[tuple[Path, str]] = []
|
||||
var_dots_needed: list[tuple[Path, list[str]]] = []
|
||||
|
||||
for mdx_path in sorted(DOCS_DIR.rglob("*.mdx")):
|
||||
blocks = extract_dot_blocks(mdx_path)
|
||||
if not blocks:
|
||||
continue
|
||||
|
||||
pdir = page_dir(mdx_path)
|
||||
if str(pdir) in skip_pages:
|
||||
print(f" SKIP {pdir} (excluded)")
|
||||
continue
|
||||
|
||||
full_blocks = [b for b in blocks if b["is_full"]]
|
||||
snippet_blocks = [b for b in blocks if not b["is_full"]]
|
||||
|
||||
if not full_blocks:
|
||||
skipped_snippets += len(snippet_blocks)
|
||||
continue
|
||||
|
||||
out_dir = OUTPUT_DIR / pdir
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
seen: set[str] = set()
|
||||
for i, block in enumerate(full_blocks):
|
||||
filename = derive_filename(block, i)
|
||||
if filename in seen:
|
||||
base, ext = os.path.splitext(filename)
|
||||
n = 2
|
||||
while f"{base}-{n:02d}{ext}" in seen:
|
||||
n += 1
|
||||
filename = f"{base}-{n:02d}{ext}"
|
||||
seen.add(filename)
|
||||
out_path = out_dir / filename
|
||||
out_path.write_text(block["code"])
|
||||
extracted += 1
|
||||
print(f" WRITE {out_path.relative_to(OUTPUT_DIR)} ({block['num_lines']} lines)")
|
||||
|
||||
# Check for prompt refs
|
||||
for ref in find_prompt_refs(block["code"]):
|
||||
prompt_stubs_needed.append((out_dir, ref))
|
||||
|
||||
# Check for custom vars
|
||||
custom_vars = find_custom_vars(block["code"])
|
||||
if custom_vars:
|
||||
var_dots_needed.append((out_path, custom_vars))
|
||||
|
||||
skipped_snippets += len(snippet_blocks)
|
||||
|
||||
# Create prompt stubs
|
||||
created_stubs = set()
|
||||
for dot_dir, ref in prompt_stubs_needed:
|
||||
stub_path = dot_dir / ref
|
||||
if str(stub_path) in created_stubs:
|
||||
continue
|
||||
stub_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
stub_path.write_text("Stub prompt for testing.\n")
|
||||
created_stubs.add(str(stub_path))
|
||||
print(f" STUB {stub_path.relative_to(OUTPUT_DIR)}")
|
||||
|
||||
# Create run.toml files for variable-using DOTs
|
||||
for dot_path, vars_list in var_dots_needed:
|
||||
toml_name = f"run-{dot_path.stem}.toml"
|
||||
toml_path = dot_path.parent / toml_name
|
||||
# Extract goal from the DOT if possible
|
||||
dot_content = dot_path.read_text()
|
||||
goal_match = re.search(r'goal\s*=\s*"([^"]*)"', dot_content)
|
||||
goal = goal_match.group(1) if goal_match else "Test workflow"
|
||||
|
||||
lines = [
|
||||
'version = 1',
|
||||
f'goal = "{goal}"',
|
||||
f'graph = "{dot_path.name}"',
|
||||
'',
|
||||
'[vars]',
|
||||
]
|
||||
for v in vars_list:
|
||||
lines.append(f'{v} = "test-{v}"')
|
||||
lines.append('')
|
||||
|
||||
toml_path.write_text("\n".join(lines))
|
||||
print(f" TOML {toml_path.relative_to(OUTPUT_DIR)} (vars: {', '.join(vars_list)})")
|
||||
|
||||
print(f"\nDone: {extracted} full workflows extracted, {skipped_snippets} snippets skipped")
|
||||
print(f" {len(created_stubs)} prompt stubs created")
|
||||
print(f" {len(var_dots_needed)} run.toml configs created")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
16
test/docs/getting-started/why-arc/plan-implement.dot
Normal file
16
test/docs/getting-started/why-arc/plan-implement.dot
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
digraph PlanImplement {
|
||||
graph [goal="Plan, approve, implement, and simplify a change"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
plan [label="Plan", prompt="Analyze the goal and codebase. Write a step-by-step plan.", reasoning_effort="high"]
|
||||
approve [shape=hexagon, label="Approve Plan"]
|
||||
implement [label="Implement", prompt="Read plan.md and implement every step."]
|
||||
simplify [label="Simplify", prompt="Review the changes for clarity and correctness."]
|
||||
|
||||
start -> plan -> approve
|
||||
approve -> implement [label="[A] Approve"]
|
||||
approve -> plan [label="[R] Revise"]
|
||||
implement -> simplify -> exit
|
||||
}
|
||||
48
test/docs/reference/dot-language/implement-feature.dot
Normal file
48
test/docs/reference/dot-language/implement-feature.dot
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
digraph ImplementFeature {
|
||||
graph [
|
||||
goal="Implement a feature with tests and code review",
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-haiku-4-5; llm_provider: anthropic; reasoning_effort: low; }
|
||||
.coding { llm_model: claude-sonnet-4-5; llm_provider: anthropic; reasoning_effort: high; }
|
||||
#review { llm_model: claude-sonnet-4-5; llm_provider: anthropic; reasoning_effort: high; }
|
||||
"
|
||||
]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
// Planning phase
|
||||
plan [label="Plan", shape=tab, prompt="Create a detailed implementation plan for: $goal"]
|
||||
|
||||
// Human approval
|
||||
approve [shape=hexagon, label="Approve Plan"]
|
||||
|
||||
// Implementation (threaded for context continuity)
|
||||
subgraph cluster_impl {
|
||||
label = "Implementation"
|
||||
node [thread_id="impl", fidelity="full"]
|
||||
implement [label="Implement", class="coding", prompt="Implement the approved plan."]
|
||||
test [label="Write Tests", class="coding", prompt="Write comprehensive tests."]
|
||||
}
|
||||
|
||||
// Validation
|
||||
validate [label="Run Tests", shape=parallelogram, script="cargo test 2>&1 || true"]
|
||||
gate [shape=diamond, label="Tests passing?"]
|
||||
|
||||
// Review
|
||||
review [label="Code Review", shape=tab, prompt="Review the implementation for correctness."]
|
||||
|
||||
// Wiring
|
||||
start -> plan -> approve
|
||||
|
||||
approve -> implement [label="[A] Approve"]
|
||||
approve -> plan [label="[R] Revise"]
|
||||
|
||||
implement -> test -> validate -> gate
|
||||
|
||||
gate -> review [label="Pass", condition="outcome=success"]
|
||||
gate -> implement [label="Fix"]
|
||||
|
||||
review -> exit
|
||||
}
|
||||
12
test/docs/reference/dot-language/my-workflow.dot
Normal file
12
test/docs/reference/dot-language/my-workflow.dot
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
digraph MyWorkflow {
|
||||
graph [goal="Describe the project"]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
scan [label="Scan Files", shape=parallelogram, script="find . -type f | head -30"]
|
||||
analyze [label="Analyze", shape=tab, prompt="Summarize the project structure."]
|
||||
|
||||
start -> scan -> analyze -> exit
|
||||
}
|
||||
87
test/docs/run_tests.sh
Executable file
87
test/docs/run_tests.sh
Executable file
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
ARC="${ARC:-$REPO_ROOT/target/release/arc}"
|
||||
|
||||
PHASE="${1:-validate}"
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
total=0
|
||||
|
||||
run_one() {
|
||||
local dot="$1"
|
||||
local rel
|
||||
rel="$(realpath --relative-to="$SCRIPT_DIR" "$dot" 2>/dev/null || echo "$dot")"
|
||||
|
||||
# Check for companion run.toml (run-<stem>.toml in same dir)
|
||||
local stem
|
||||
stem="$(basename "${dot%.dot}")"
|
||||
local toml
|
||||
toml="$(dirname "$dot")/run-${stem}.toml"
|
||||
|
||||
total=$((total + 1))
|
||||
|
||||
case "$PHASE" in
|
||||
validate)
|
||||
if "$ARC" validate "$dot" 2>&1; then
|
||||
echo " PASS $rel"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
echo " FAIL $rel"
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
;;
|
||||
dry-run)
|
||||
local target="$dot"
|
||||
[[ -f "$toml" ]] && target="$toml"
|
||||
if "$ARC" run start "$target" --dry-run --auto-approve 2>&1; then
|
||||
echo " PASS $rel"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
echo " FAIL $rel"
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
;;
|
||||
haiku)
|
||||
local target="$dot"
|
||||
[[ -f "$toml" ]] && target="$toml"
|
||||
if "$ARC" run start "$target" --model claude-haiku-4-5 --auto-approve 2>&1; then
|
||||
echo " PASS $rel"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
echo " FAIL $rel"
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
;;
|
||||
full)
|
||||
local target="$dot"
|
||||
[[ -f "$toml" ]] && target="$toml"
|
||||
if "$ARC" run start "$target" --auto-approve 2>&1; then
|
||||
echo " PASS $rel"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
echo " FAIL $rel"
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 <validate|dry-run|haiku|full>"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
echo "=== Phase: $PHASE ==="
|
||||
echo ""
|
||||
|
||||
while IFS= read -r dot; do
|
||||
run_one "$dot"
|
||||
done < <(find "$SCRIPT_DIR" -name '*.dot' | sort)
|
||||
|
||||
echo ""
|
||||
echo "=== Results: $pass passed, $fail failed, $total total ==="
|
||||
|
||||
[[ $fail -eq 0 ]]
|
||||
16
test/docs/tutorials/branch-loop/branch-loop.dot
Normal file
16
test/docs/tutorials/branch-loop/branch-loop.dot
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
digraph BranchLoop {
|
||||
graph [goal="Create a Python script that passes its test suite"]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
plan [label="Plan", prompt="Plan a small Python script (fizzbuzz.py) and a test file (test_fizzbuzz.py) using pytest. Describe what you will create.", shape=tab, reasoning_effort="low"]
|
||||
implement [label="Implement", prompt="Create fizzbuzz.py and test_fizzbuzz.py as planned. Write the files to disk."]
|
||||
validate [label="Validate", shape=parallelogram, script="python -m pytest test_fizzbuzz.py -v 2>&1 || true"]
|
||||
gate [shape=diamond, label="Tests passing?"]
|
||||
|
||||
start -> plan -> implement -> validate -> gate
|
||||
gate -> exit [label="Pass", condition="outcome=success"]
|
||||
gate -> implement [label="Fix"]
|
||||
}
|
||||
37
test/docs/tutorials/ensemble/ensemble.dot
Normal file
37
test/docs/tutorials/ensemble/ensemble.dot
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
digraph Ensemble {
|
||||
graph [
|
||||
goal="Get independent opinions from multiple providers, then synthesize",
|
||||
model_stylesheet="
|
||||
#opus { llm_model: claude-opus-4-6; llm_provider: anthropic; }
|
||||
#gemini { llm_model: gemini-3.1-pro-preview; llm_provider: gemini; }
|
||||
#codex { llm_model: gpt-5.3-codex; llm_provider: openai; }
|
||||
#mercury { llm_model: mercury-2; llm_provider: inception; }
|
||||
#synth { llm_model: claude-opus-4-6; llm_provider: anthropic; reasoning_effort: high; }
|
||||
"
|
||||
]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
fork [label="Fan Out", shape=component, join_policy="wait_all", error_policy="continue"]
|
||||
|
||||
opus [label="Opus", prompt="Analyze the goal. Provide your independent assessment, recommendations, and any code or prose needed. Be thorough.", shape=tab]
|
||||
gemini [label="Gemini", prompt="Analyze the goal. Provide your independent assessment, recommendations, and any code or prose needed. Be thorough.", shape=tab]
|
||||
codex [label="Codex", prompt="Analyze the goal. Provide your independent assessment, recommendations, and any code or prose needed. Be thorough.", shape=tab]
|
||||
mercury [label="Mercury", prompt="Analyze the goal. Provide your independent assessment, recommendations, and any code or prose needed. Be thorough.", shape=tab]
|
||||
|
||||
merge [label="Merge", shape=tripleoctagon]
|
||||
synth [label="Synthesize", prompt="You have received independent analyses from four different models (Opus, Gemini, Codex, Mercury). Compare their perspectives: identify consensus, highlight disagreements, and synthesize the strongest ideas into a single coherent recommendation. Note where models agreed and where they diverged.", shape=tab]
|
||||
|
||||
start -> fork
|
||||
fork -> opus
|
||||
fork -> gemini
|
||||
fork -> codex
|
||||
fork -> mercury
|
||||
opus -> merge
|
||||
gemini -> merge
|
||||
codex -> merge
|
||||
mercury -> merge
|
||||
merge -> synth -> exit
|
||||
}
|
||||
11
test/docs/tutorials/hello-world/hello.dot
Normal file
11
test/docs/tutorials/hello-world/hello.dot
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
digraph Hello {
|
||||
graph [goal="Write a haiku about software workflows"]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
compose [label="Compose", prompt="Write a haiku (5-7-5 syllable) about software workflows. Output only the haiku, nothing else.", shape=tab, reasoning_effort="low"]
|
||||
|
||||
start -> compose -> exit
|
||||
}
|
||||
11
test/docs/tutorials/hello-world/sub-agent.dot
Normal file
11
test/docs/tutorials/hello-world/sub-agent.dot
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
digraph SubAgent {
|
||||
graph [goal="Research and summarize using a sub-agent"]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
research [label="Research", prompt="You have a sub-agent available via the spawn_agent tool. Spawn a sub-agent to list the files in the current directory and read the first 10 lines of any README or CLAUDE.md. Then, using the sub-agent's findings, write a 2-sentence summary of the project."]
|
||||
|
||||
start -> research -> exit
|
||||
}
|
||||
11
test/docs/tutorials/hello-world/tool-use.dot
Normal file
11
test/docs/tutorials/hello-world/tool-use.dot
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
digraph ToolUse {
|
||||
graph [goal="Explore the current directory using shell tools"]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
explore [label="Explore", prompt="Use bash to list the files in the current directory, then read the first 5 lines of any README or CLAUDE.md file you find. Summarize what this project is about in 2-3 sentences."]
|
||||
|
||||
start -> explore -> exit
|
||||
}
|
||||
21
test/docs/tutorials/multi-model/multi-model.dot
Normal file
21
test/docs/tutorials/multi-model/multi-model.dot
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
digraph MultiModel {
|
||||
graph [
|
||||
goal="Build and review a utility function using multiple models",
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-haiku-4-5; llm_provider: anthropic; reasoning_effort: low; }
|
||||
.coding { llm_model: claude-sonnet-4-5; llm_provider: anthropic; reasoning_effort: high; }
|
||||
#review { llm_model: claude-sonnet-4-5; llm_provider: anthropic; reasoning_effort: high; }
|
||||
"
|
||||
]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
spec [label="Write Spec", prompt="Write a brief spec for a TypeScript string utility module with 3 functions: slugify, truncate, and capitalize. Output the spec only.", shape=tab]
|
||||
implement [label="Implement", prompt="Implement the TypeScript string utility module from the spec. Write it to string-utils.ts.", class="coding"]
|
||||
test [label="Write Tests", prompt="Write tests for the string utility module using Bun's test runner. Write to string-utils.test.ts.", class="coding"]
|
||||
review [label="Code Review", prompt="Review the implementation and tests. Check for edge cases, type safety, and correctness. Provide a brief verdict.", shape=tab]
|
||||
|
||||
start -> spec -> implement -> test -> review -> exit
|
||||
}
|
||||
25
test/docs/tutorials/parallel-review/parallel.dot
Normal file
25
test/docs/tutorials/parallel-review/parallel.dot
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
digraph Parallel {
|
||||
graph [goal="Perform a multi-perspective code review"]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
fork [label="Fork Analysis", shape=component, join_policy="wait_all", error_policy="continue"]
|
||||
|
||||
security [label="Security Audit", prompt="Examine the codebase for security concerns: hardcoded secrets, injection risks, unsafe dependencies. List findings as bullet points.", shape=tab, reasoning_effort="low"]
|
||||
architecture [label="Architecture Review", prompt="Assess the codebase architecture: separation of concerns, dependency structure, modularity. List findings as bullet points.", shape=tab, reasoning_effort="low"]
|
||||
quality [label="Code Quality", prompt="Check code quality: naming conventions, dead code, test coverage gaps, error handling. List findings as bullet points.", shape=tab, reasoning_effort="low"]
|
||||
|
||||
merge [label="Merge Findings", shape=tripleoctagon]
|
||||
report [label="Final Report", prompt="Synthesize the security, architecture, and code quality findings into a prioritized summary report with top 5 action items.", shape=tab]
|
||||
|
||||
start -> fork
|
||||
fork -> security
|
||||
fork -> architecture
|
||||
fork -> quality
|
||||
security -> merge
|
||||
architecture -> merge
|
||||
quality -> merge
|
||||
merge -> report -> exit
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
Stub prompt for testing.
|
||||
17
test/docs/tutorials/plan-implement/plan-implement.dot
Normal file
17
test/docs/tutorials/plan-implement/plan-implement.dot
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
digraph PlanImplement {
|
||||
graph [goal="Plan, approve, implement, and simplify a change"]
|
||||
rankdir=LR
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
plan [label="Plan", prompt="Analyze the goal and codebase. Write a clear, step-by-step implementation plan to a Markdown file called plan.md. Include what files will change and why.", reasoning_effort="high"]
|
||||
approve [shape=hexagon, label="Approve Plan"]
|
||||
implement [label="Implement", prompt="Read plan.md and implement every step. Make all the code changes described in the plan."]
|
||||
simplify [label="Simplify", prompt="@docs-internal/prompts/simplify.md"]
|
||||
|
||||
start -> plan -> approve
|
||||
approve -> implement [label="[A] Approve"]
|
||||
approve -> plan [label="[R] Revise"]
|
||||
implement -> simplify -> exit
|
||||
}
|
||||
40
test/docs/workflows/human-in-the-loop/hitl-patterns.dot
Normal file
40
test/docs/workflows/human-in-the-loop/hitl-patterns.dot
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Assembled from docs/workflows/human-in-the-loop.mdx snippets
|
||||
// Tests human gates: basic, freeform, and default_choice
|
||||
|
||||
digraph HitlPatterns {
|
||||
graph [goal="Exercise human-in-the-loop patterns from the HITL docs page"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
plan [label="Plan", prompt="Create an implementation plan."]
|
||||
implement [label="Implement", prompt="Implement the plan."]
|
||||
custom [label="Custom", prompt="Handle custom input."]
|
||||
|
||||
// Line 13-17: Basic human gate with accelerators
|
||||
approve [shape=hexagon, label="Approve Plan"]
|
||||
|
||||
// Line 39-43: Freeform input on human gate
|
||||
review [shape=hexagon, label="Review Changes"]
|
||||
|
||||
// Line 53: Default choice on timeout
|
||||
deploy_gate [shape=hexagon, label="Deploy?", human.default_choice="approve"]
|
||||
|
||||
// Wiring
|
||||
start -> plan -> approve
|
||||
|
||||
approve -> implement [label="[A] Approve"]
|
||||
approve -> plan [label="[R] Revise"]
|
||||
approve -> exit [label="[S] Skip"]
|
||||
|
||||
implement -> review
|
||||
|
||||
review -> deploy_gate [label="[A] Approve"]
|
||||
review -> plan [label="[R] Revise"]
|
||||
review -> custom [freeform=true]
|
||||
|
||||
custom -> deploy_gate
|
||||
|
||||
deploy_gate -> exit [label="[A] Approve"]
|
||||
deploy_gate -> plan [label="[R] Revise"]
|
||||
}
|
||||
69
test/docs/workflows/stages-and-nodes/all-node-types.dot
Normal file
69
test/docs/workflows/stages-and-nodes/all-node-types.dot
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Assembled from docs/workflows/stages-and-nodes.mdx snippets
|
||||
// Tests every node type documented on that page
|
||||
|
||||
digraph AllNodeTypes {
|
||||
graph [goal="Exercise every node type from the stages-and-nodes docs page"]
|
||||
|
||||
// Line 23: Start node
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
|
||||
// Line 33: Exit node
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
// Line 43: Agent node
|
||||
implement [label="Implement", prompt="Read plan.md and implement every step."]
|
||||
|
||||
// Line 74-81: Subgraph cluster with thread_id
|
||||
subgraph cluster_impl {
|
||||
node [fidelity="full", thread_id="impl"]
|
||||
plan_thread [label="Plan Thread"]
|
||||
implement_thread [label="Implement Thread"]
|
||||
review_thread [label="Review Thread"]
|
||||
}
|
||||
|
||||
// Line 90: Prompt (tab) node
|
||||
spec [label="Write Spec", shape=tab, prompt="Write a brief spec for a string utility module."]
|
||||
|
||||
// Line 102: Command (parallelogram) node
|
||||
test [label="Run Tests", shape=parallelogram, script="echo 'tests passed' 2>&1 || true"]
|
||||
|
||||
// Line 117-120: Human (hexagon) node
|
||||
approve [shape=hexagon, label="Approve Plan"]
|
||||
|
||||
// Line 132: Wait (insulator) node
|
||||
cooldown [label="Wait 1s", shape=insulator, duration="1s"]
|
||||
|
||||
// Line 146-149: Conditional (diamond) node
|
||||
gate [shape=diamond, label="Tests passing?"]
|
||||
|
||||
// Line 161-165: Parallel (component) fan-out node
|
||||
fork [label="Fan Out", shape=component, join_policy="wait_all", error_policy="continue"]
|
||||
|
||||
// Line 198-203: Merge (tripleoctagon) fan-in node
|
||||
merge [label="Merge Results", shape=tripleoctagon]
|
||||
|
||||
// Branches for fan-out
|
||||
security [label="Security", prompt="Check for security issues."]
|
||||
architecture [label="Architecture", prompt="Check architecture."]
|
||||
|
||||
// Wiring
|
||||
start -> spec -> implement -> test -> gate
|
||||
|
||||
gate -> approve [label="Pass", condition="outcome=success"]
|
||||
gate -> implement [label="Fix"]
|
||||
|
||||
approve -> plan_thread [label="[A] Approve"]
|
||||
approve -> implement [label="[R] Revise"]
|
||||
|
||||
plan_thread -> implement_thread -> review_thread -> cooldown
|
||||
|
||||
cooldown -> fork
|
||||
|
||||
fork -> security
|
||||
fork -> architecture
|
||||
|
||||
security -> merge
|
||||
architecture -> merge
|
||||
|
||||
merge -> exit
|
||||
}
|
||||
20
test/docs/workflows/stylesheets/example.dot
Normal file
20
test/docs/workflows/stylesheets/example.dot
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
digraph Example {
|
||||
graph [
|
||||
goal="Build and review a utility function",
|
||||
model_stylesheet="
|
||||
* { llm_model: claude-haiku-4-5; llm_provider: anthropic; }
|
||||
.coding { llm_model: claude-sonnet-4-5; reasoning_effort: high; }
|
||||
#review { llm_model: gemini-3.1-pro-preview; llm_provider: gemini; }
|
||||
"
|
||||
]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
spec [label="Write Spec"]
|
||||
implement [label="Implement", class="coding"]
|
||||
test [label="Write Tests", class="coding"]
|
||||
review [label="Code Review"]
|
||||
|
||||
start -> spec -> implement -> test -> review -> exit
|
||||
}
|
||||
76
test/docs/workflows/transitions/transition-patterns.dot
Normal file
76
test/docs/workflows/transitions/transition-patterns.dot
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Assembled from docs/workflows/transitions.mdx snippets
|
||||
// Tests conditions, human gates, unconditional edges, weights, and agent routing
|
||||
|
||||
digraph TransitionPatterns {
|
||||
graph [goal="Exercise every transition pattern from the transitions docs page"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
// Line 103-114: Agent transition with routing JSON
|
||||
review [
|
||||
label="Review",
|
||||
shape=tab,
|
||||
prompt="Review the implementation for correctness and \
|
||||
code quality. If changes are needed, respond with: \
|
||||
{\"preferred_next_label\": \"fix\"}. If everything \
|
||||
looks good, respond with: \
|
||||
{\"preferred_next_label\": \"approve\"}."
|
||||
]
|
||||
|
||||
fix [label="Fix", prompt="Fix the issues found in the review."]
|
||||
|
||||
// Line 32-33: Condition on edges
|
||||
gate [shape=diamond, label="Tests passing?"]
|
||||
|
||||
// Line 60: Boolean flag condition (truthiness check)
|
||||
flag_gate [shape=diamond, label="Flag check"]
|
||||
|
||||
// Line 68-79: Compound conditions
|
||||
deploy_gate [shape=diamond, label="Deploy gate"]
|
||||
|
||||
deploy [label="Deploy", prompt="Deploy the changes."]
|
||||
proceed [label="Proceed", prompt="Proceed with next step."]
|
||||
retry [label="Retry", prompt="Retry the operation."]
|
||||
|
||||
// Line 123-128: Human gate transitions
|
||||
approve [shape=hexagon, label="Approve Plan"]
|
||||
plan [label="Plan", prompt="Create a plan."]
|
||||
skip [label="Skip", prompt="Skip this step."]
|
||||
|
||||
// Line 137: Chain syntax (unconditional)
|
||||
start -> plan -> review
|
||||
|
||||
review -> fix [label="Fix"]
|
||||
review -> gate [label="Approve"]
|
||||
|
||||
fix -> review
|
||||
|
||||
// Line 32-33: Conditional edges
|
||||
gate -> exit [label="Pass", condition="outcome=success"]
|
||||
gate -> flag_gate [label="Fix", condition="outcome=fail"]
|
||||
gate -> exit [label="Fallback"]
|
||||
|
||||
// Line 60: Truthiness check
|
||||
flag_gate -> deploy_gate [condition="outcome=success"]
|
||||
flag_gate -> retry
|
||||
|
||||
// Line 68-70: Compound condition
|
||||
deploy_gate -> deploy [condition="outcome=success && context.tests_passed=true"]
|
||||
// Line 72: OR condition
|
||||
deploy_gate -> proceed [condition="outcome=success || outcome=partial_success"]
|
||||
deploy_gate -> exit [label="Fallback"]
|
||||
|
||||
deploy -> approve
|
||||
|
||||
// Line 123-128: Human gate edges
|
||||
approve -> exit [label="[A] Approve"]
|
||||
approve -> plan [label="[R] Revise"]
|
||||
approve -> skip [label="[S] Skip"]
|
||||
|
||||
skip -> exit
|
||||
proceed -> exit
|
||||
retry -> review
|
||||
|
||||
// Line 152-153: Weight tiebreaking (tested on deploy_gate fallback)
|
||||
}
|
||||
11
test/docs/workflows/variables/check.dot
Normal file
11
test/docs/workflows/variables/check.dot
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
digraph Check {
|
||||
graph [goal="Run tests for $repo_name"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
clone [label="Clone", shape=parallelogram, script="git clone $repo_url repo"]
|
||||
test [label="Test", prompt="Run the $language test suite in the repo/ directory."]
|
||||
|
||||
start -> clone -> test -> exit
|
||||
}
|
||||
10
test/docs/workflows/variables/example.dot
Normal file
10
test/docs/workflows/variables/example.dot
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
digraph Example {
|
||||
graph [goal="Implement the login feature"]
|
||||
|
||||
start [shape=Mdiamond, label="Start"]
|
||||
exit [shape=Msquare, label="Exit"]
|
||||
|
||||
plan [label="Plan", prompt="Create a plan for: $goal"]
|
||||
|
||||
start -> plan -> exit
|
||||
}
|
||||
8
test/docs/workflows/variables/run-check.toml
Normal file
8
test/docs/workflows/variables/run-check.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
version = 1
|
||||
goal = "Run tests for $repo_name"
|
||||
graph = "check.dot"
|
||||
|
||||
[vars]
|
||||
language = "test-language"
|
||||
repo_name = "test-repo_name"
|
||||
repo_url = "test-repo_url"
|
||||
Loading…
Add table
Reference in a new issue