diff --git a/docs/examples/definition-of-done.mdx b/docs/examples/definition-of-done.mdx index 3c878ca0a..ce9a96dd3 100644 --- a/docs/examples/definition-of-done.mdx +++ b/docs/examples/definition-of-done.mdx @@ -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"] diff --git a/docs/examples/semantic-port.mdx b/docs/examples/semantic-port.mdx index 4517ee6e5..508245254 100644 --- a/docs/examples/semantic-port.mdx +++ b/docs/examples/semantic-port.mdx @@ -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 diff --git a/test/docs/CHECKLIST.md b/test/docs/CHECKLIST.md new file mode 100644 index 000000000..09d4ac911 --- /dev/null +++ b/test/docs/CHECKLIST.md @@ -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 +``` diff --git a/test/docs/agents/outputs/output-patterns.dot b/test/docs/agents/outputs/output-patterns.dot new file mode 100644 index 000000000..dbf646bff --- /dev/null +++ b/test/docs/agents/outputs/output-patterns.dot @@ -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 +} diff --git a/test/docs/agents/prompts/pipeline.dot b/test/docs/agents/prompts/pipeline.dot new file mode 100644 index 000000000..286d8fb35 --- /dev/null +++ b/test/docs/agents/prompts/pipeline.dot @@ -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 +} diff --git a/test/docs/changelog/2026-03-05/new-features.dot b/test/docs/changelog/2026-03-05/new-features.dot new file mode 100644 index 000000000..685ad6a0f --- /dev/null +++ b/test/docs/changelog/2026-03-05/new-features.dot @@ -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 +} diff --git a/test/docs/core-concepts/agents/backend-demo.dot b/test/docs/core-concepts/agents/backend-demo.dot new file mode 100644 index 000000000..449260cb9 --- /dev/null +++ b/test/docs/core-concepts/agents/backend-demo.dot @@ -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 +} diff --git a/test/docs/core-concepts/models/example.dot b/test/docs/core-concepts/models/example.dot new file mode 100644 index 000000000..a127b74fc --- /dev/null +++ b/test/docs/core-concepts/models/example.dot @@ -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 +} diff --git a/test/docs/core-concepts/workflows/my-workflow.dot b/test/docs/core-concepts/workflows/my-workflow.dot new file mode 100644 index 000000000..cc6abfee2 --- /dev/null +++ b/test/docs/core-concepts/workflows/my-workflow.dot @@ -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 +} diff --git a/test/docs/examples/clone-substack/clone-substack.dot b/test/docs/examples/clone-substack/clone-substack.dot new file mode 100644 index 000000000..d16fb48d1 --- /dev/null +++ b/test/docs/examples/clone-substack/clone-substack.dot @@ -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"] +} diff --git a/test/docs/examples/definition-of-done/spec-dod-multimodel.dot b/test/docs/examples/definition-of-done/spec-dod-multimodel.dot new file mode 100644 index 000000000..d606ee15e --- /dev/null +++ b/test/docs/examples/definition-of-done/spec-dod-multimodel.dot @@ -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. 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"] +} diff --git a/test/docs/examples/definition-of-done/spec-dod.dot b/test/docs/examples/definition-of-done/spec-dod.dot new file mode 100644 index 000000000..866ebf269 --- /dev/null +++ b/test/docs/examples/definition-of-done/spec-dod.dot @@ -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"] +} diff --git a/test/docs/examples/nlspec-conformance/n-l-spec-conformance.dot b/test/docs/examples/nlspec-conformance/n-l-spec-conformance.dot new file mode 100644 index 000000000..395b4c4d0 --- /dev/null +++ b/test/docs/examples/nlspec-conformance/n-l-spec-conformance.dot @@ -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"] +} diff --git a/test/docs/examples/nlspec-conformance/prompts/fix.md b/test/docs/examples/nlspec-conformance/prompts/fix.md new file mode 100644 index 000000000..1aa36a1a2 --- /dev/null +++ b/test/docs/examples/nlspec-conformance/prompts/fix.md @@ -0,0 +1 @@ +Stub prompt for testing. diff --git a/test/docs/examples/nlspec-conformance/prompts/implement.md b/test/docs/examples/nlspec-conformance/prompts/implement.md new file mode 100644 index 000000000..1aa36a1a2 --- /dev/null +++ b/test/docs/examples/nlspec-conformance/prompts/implement.md @@ -0,0 +1 @@ +Stub prompt for testing. diff --git a/test/docs/examples/nlspec-conformance/prompts/plan.md b/test/docs/examples/nlspec-conformance/prompts/plan.md new file mode 100644 index 000000000..1aa36a1a2 --- /dev/null +++ b/test/docs/examples/nlspec-conformance/prompts/plan.md @@ -0,0 +1 @@ +Stub prompt for testing. diff --git a/test/docs/examples/semantic-port/semantic-port.dot b/test/docs/examples/semantic-port/semantic-port.dot new file mode 100644 index 000000000..43ac75814 --- /dev/null +++ b/test/docs/examples/semantic-port/semantic-port.dot @@ -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 `\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 ` 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 acknowledged`\n\ + 2. Commit: `git add ledger/ && git commit -m \"semport: acknowledge - \"`\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 implemented`\n\ + 2. Commit all changes:\n\ + `git add -A && git commit -m \"semport: implement - \"`\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 +} diff --git a/test/docs/examples/solitaire/build-solitaire.dot b/test/docs/examples/solitaire/build-solitaire.dot new file mode 100644 index 000000000..d774f7a3a --- /dev/null +++ b/test/docs/examples/solitaire/build-solitaire.dot @@ -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 +} diff --git a/test/docs/execution/context/example.dot b/test/docs/execution/context/example.dot new file mode 100644 index 000000000..1a04e4bef --- /dev/null +++ b/test/docs/execution/context/example.dot @@ -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 +} diff --git a/test/docs/execution/failures/example-02.dot b/test/docs/execution/failures/example-02.dot new file mode 100644 index 000000000..872a15fc2 --- /dev/null +++ b/test/docs/execution/failures/example-02.dot @@ -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 +} diff --git a/test/docs/execution/failures/example-03.dot b/test/docs/execution/failures/example-03.dot new file mode 100644 index 000000000..4bde8526b --- /dev/null +++ b/test/docs/execution/failures/example-03.dot @@ -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 +} diff --git a/test/docs/execution/failures/example-04.dot b/test/docs/execution/failures/example-04.dot new file mode 100644 index 000000000..622d37f01 --- /dev/null +++ b/test/docs/execution/failures/example-04.dot @@ -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 +} diff --git a/test/docs/execution/failures/example.dot b/test/docs/execution/failures/example.dot new file mode 100644 index 000000000..fe0eb4b71 --- /dev/null +++ b/test/docs/execution/failures/example.dot @@ -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 +} diff --git a/test/docs/execution/interviews/default-choice.dot b/test/docs/execution/interviews/default-choice.dot new file mode 100644 index 000000000..f78a5c233 --- /dev/null +++ b/test/docs/execution/interviews/default-choice.dot @@ -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 +} diff --git a/test/docs/execution/run-configuration/c-i.dot b/test/docs/execution/run-configuration/c-i.dot new file mode 100644 index 000000000..9eced6dec --- /dev/null +++ b/test/docs/execution/run-configuration/c-i.dot @@ -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 +} diff --git a/test/docs/execution/run-configuration/run-c-i.toml b/test/docs/execution/run-configuration/run-c-i.toml new file mode 100644 index 000000000..8aac9e239 --- /dev/null +++ b/test/docs/execution/run-configuration/run-c-i.toml @@ -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" diff --git a/test/docs/extract_dots.py b/test/docs/extract_dots.py new file mode 100644 index 000000000..8528a0ddf --- /dev/null +++ b/test/docs/extract_dots.py @@ -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"(? 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() diff --git a/test/docs/getting-started/why-arc/plan-implement.dot b/test/docs/getting-started/why-arc/plan-implement.dot new file mode 100644 index 000000000..351cdc4d7 --- /dev/null +++ b/test/docs/getting-started/why-arc/plan-implement.dot @@ -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 +} diff --git a/test/docs/reference/dot-language/implement-feature.dot b/test/docs/reference/dot-language/implement-feature.dot new file mode 100644 index 000000000..3db9442d7 --- /dev/null +++ b/test/docs/reference/dot-language/implement-feature.dot @@ -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 +} diff --git a/test/docs/reference/dot-language/my-workflow.dot b/test/docs/reference/dot-language/my-workflow.dot new file mode 100644 index 000000000..a7e30046c --- /dev/null +++ b/test/docs/reference/dot-language/my-workflow.dot @@ -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 +} diff --git a/test/docs/run_tests.sh b/test/docs/run_tests.sh new file mode 100755 index 000000000..6008e9189 --- /dev/null +++ b/test/docs/run_tests.sh @@ -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-.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 " + 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 ]] diff --git a/test/docs/tutorials/branch-loop/branch-loop.dot b/test/docs/tutorials/branch-loop/branch-loop.dot new file mode 100644 index 000000000..ab9a77ebe --- /dev/null +++ b/test/docs/tutorials/branch-loop/branch-loop.dot @@ -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"] +} diff --git a/test/docs/tutorials/ensemble/ensemble.dot b/test/docs/tutorials/ensemble/ensemble.dot new file mode 100644 index 000000000..efd9ab99f --- /dev/null +++ b/test/docs/tutorials/ensemble/ensemble.dot @@ -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 +} diff --git a/test/docs/tutorials/hello-world/hello.dot b/test/docs/tutorials/hello-world/hello.dot new file mode 100644 index 000000000..2d245918e --- /dev/null +++ b/test/docs/tutorials/hello-world/hello.dot @@ -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 +} diff --git a/test/docs/tutorials/hello-world/sub-agent.dot b/test/docs/tutorials/hello-world/sub-agent.dot new file mode 100644 index 000000000..385fd9102 --- /dev/null +++ b/test/docs/tutorials/hello-world/sub-agent.dot @@ -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 +} diff --git a/test/docs/tutorials/hello-world/tool-use.dot b/test/docs/tutorials/hello-world/tool-use.dot new file mode 100644 index 000000000..a199ba49d --- /dev/null +++ b/test/docs/tutorials/hello-world/tool-use.dot @@ -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 +} diff --git a/test/docs/tutorials/multi-model/multi-model.dot b/test/docs/tutorials/multi-model/multi-model.dot new file mode 100644 index 000000000..90c97a67d --- /dev/null +++ b/test/docs/tutorials/multi-model/multi-model.dot @@ -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 +} diff --git a/test/docs/tutorials/parallel-review/parallel.dot b/test/docs/tutorials/parallel-review/parallel.dot new file mode 100644 index 000000000..9a79c2940 --- /dev/null +++ b/test/docs/tutorials/parallel-review/parallel.dot @@ -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 +} diff --git a/test/docs/tutorials/plan-implement/docs-internal/prompts/simplify.md b/test/docs/tutorials/plan-implement/docs-internal/prompts/simplify.md new file mode 100644 index 000000000..1aa36a1a2 --- /dev/null +++ b/test/docs/tutorials/plan-implement/docs-internal/prompts/simplify.md @@ -0,0 +1 @@ +Stub prompt for testing. diff --git a/test/docs/tutorials/plan-implement/plan-implement.dot b/test/docs/tutorials/plan-implement/plan-implement.dot new file mode 100644 index 000000000..690e9d9c8 --- /dev/null +++ b/test/docs/tutorials/plan-implement/plan-implement.dot @@ -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 +} diff --git a/test/docs/workflows/human-in-the-loop/hitl-patterns.dot b/test/docs/workflows/human-in-the-loop/hitl-patterns.dot new file mode 100644 index 000000000..c741900e9 --- /dev/null +++ b/test/docs/workflows/human-in-the-loop/hitl-patterns.dot @@ -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"] +} diff --git a/test/docs/workflows/stages-and-nodes/all-node-types.dot b/test/docs/workflows/stages-and-nodes/all-node-types.dot new file mode 100644 index 000000000..2c2f9c190 --- /dev/null +++ b/test/docs/workflows/stages-and-nodes/all-node-types.dot @@ -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 +} diff --git a/test/docs/workflows/stylesheets/example.dot b/test/docs/workflows/stylesheets/example.dot new file mode 100644 index 000000000..785142a88 --- /dev/null +++ b/test/docs/workflows/stylesheets/example.dot @@ -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 +} diff --git a/test/docs/workflows/transitions/transition-patterns.dot b/test/docs/workflows/transitions/transition-patterns.dot new file mode 100644 index 000000000..623c8467c --- /dev/null +++ b/test/docs/workflows/transitions/transition-patterns.dot @@ -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) +} diff --git a/test/docs/workflows/variables/check.dot b/test/docs/workflows/variables/check.dot new file mode 100644 index 000000000..992d1de2b --- /dev/null +++ b/test/docs/workflows/variables/check.dot @@ -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 +} diff --git a/test/docs/workflows/variables/example.dot b/test/docs/workflows/variables/example.dot new file mode 100644 index 000000000..4fc1b1d7a --- /dev/null +++ b/test/docs/workflows/variables/example.dot @@ -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 +} diff --git a/test/docs/workflows/variables/run-check.toml b/test/docs/workflows/variables/run-check.toml new file mode 100644 index 000000000..f400c4450 --- /dev/null +++ b/test/docs/workflows/variables/run-check.toml @@ -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"