fabro/test/attractor/refactor_test_moderate.dot
Bryan Helmkamp b9fe1282d3 Attractor spec hunks 9-11: edge selection fallback and default_max_retries rename
- Remove any-edge fallback from select_edge() in deterministic mode; random
  mode retains it as an enhancement over the base spec
- Restrict preferred_label and suggested_next_ids matching to unconditional
  edges only (already applied in prior work, tests added here)
- Rename default_max_retry → default_max_retries across codebase (code, docs,
  fixtures, skills) and change default from 3 to 0
- Update transitions.mdx to document edge selection cascade accurately

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 14:20:24 -04:00

400 lines
12 KiB
Text

digraph linkcheck {
graph [
goal="Build a Go CLI tool that checks URLs for broken links with configurable depth and multiple output formats",
rankdir=LR,
default_max_retries=3,
retry_target="impl_setup",
fallback_retry_target="impl_crawler",
model_stylesheet="
* { model: gemini-3-flash-preview; provider: google; reasoning_effort: medium; }
.hard { model: gemini-3-flash-preview; provider: google; reasoning_effort: high; }
.verify { model: gemini-3-flash-preview; provider: google; reasoning_effort: medium; }
.review { model: gemini-3-flash-preview; provider: google; reasoning_effort: high; }
"
]
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
// Spec expansion (vague input — bootstraps .ai/spec.md into existence)
expand_spec [
shape=box,
auto_status=true,
prompt="Given the requirements: Build a Go CLI tool called 'linkcheck' that takes a URL as input, crawls the page, finds all links, checks each link for HTTP status, and outputs a report of broken links (4xx/5xx). It should respect robots.txt, have a configurable crawl depth (default 1), and output in both human-readable and JSON formats.
Expand into a detailed spec covering:
- CLI interface (flags, arguments, exit codes)
- Package structure (cmd/, pkg/ organization)
- Core data types (Link, CrawlResult, Report, etc.)
- robots.txt parsing and respect
- HTTP client configuration (timeouts, user agent, redirects)
- Link extraction from HTML
- Status code categorization (broken vs. OK)
- Depth control mechanism
- Output formatters (text and JSON)
- Error handling
- Test plan (unit tests for each package, integration test)
Write the spec to .ai/spec.md.
Write status.json: outcome=success"
]
// Project setup
impl_setup [
shape=box,
prompt="Goal: $goal
Read .ai/spec.md. Create the Go project structure:
- Initialize go.mod for linkcheck
- Create cmd/linkcheck/main.go with CLI stub
- Create pkg/ directories: pkg/crawler/, pkg/checker/, pkg/robots/, pkg/formatter/
- Add basic README.md with build/usage instructions
Acceptance:
- `go mod init` must succeed
- `go build ./...` must pass
- Directory structure matches spec
Write status.json: outcome=success if all pass, outcome=fail with failure_reason otherwise."
]
verify_setup [
shape=box,
class="verify",
prompt="Verify project setup was completed correctly.
Run:
1. `go build ./...`
2. `go vet ./...`
3. Check that go.mod exists
4. Check that cmd/linkcheck/main.go exists
5. Check that pkg/ subdirectories exist
Write results to .ai/verify_setup.md.
Write status.json: outcome=success if ALL pass, outcome=fail with details."
]
check_setup [shape=diamond, label="Setup OK?"]
// Crawler implementation
impl_crawler [
shape=box,
class="hard",
max_retries=2,
prompt="Goal: $goal
Spec: .ai/spec.md, crawler section.
Read: cmd/linkcheck/main.go for understanding the entry point.
Implement the web crawler in pkg/crawler/:
- Crawler struct with configurable depth, user agent
- FetchPage function (HTTP GET with proper headers)
- ExtractLinks function (parse HTML, find all <a href> tags)
- Depth tracking and queue management
- URL normalization and deduplication
- Tests for all functions
Create/modify:
- pkg/crawler/crawler.go
- pkg/crawler/parser.go
- pkg/crawler/crawler_test.go
Acceptance:
- `go build ./...` must pass
- `go test ./pkg/crawler/...` must pass with all tests
Write status.json: outcome=success if all criteria pass, outcome=fail with failure_reason otherwise."
]
verify_crawler [
shape=box,
class="verify",
prompt="Verify crawler implementation was completed correctly.
Run:
1. `go build ./...`
2. `go vet ./...`
3. `go test ./pkg/crawler/... -v`
4. Check that pkg/crawler/crawler.go exists
5. Check that tests cover FetchPage and ExtractLinks
Write results to .ai/verify_crawler.md.
Write status.json: outcome=success if ALL pass, outcome=fail with details."
]
check_crawler [shape=diamond, label="Crawler OK?"]
// Robots.txt implementation
impl_robots [
shape=box,
prompt="Goal: $goal
Spec: .ai/spec.md, robots.txt section.
Read: pkg/crawler/crawler.go for types you need.
Implement robots.txt parser and checker in pkg/robots/:
- RobotsParser struct
- FetchRobotsTxt function
- IsAllowed function (check if URL path is allowed for user agent)
- Parse user-agent, disallow, allow directives
- Tests
Create/modify:
- pkg/robots/robots.go
- pkg/robots/robots_test.go
Acceptance:
- `go build ./...` must pass
- `go test ./pkg/robots/...` must pass
Write status.json: outcome=success if all criteria pass, outcome=fail with failure_reason otherwise."
]
verify_robots [
shape=box,
class="verify",
prompt="Verify robots.txt implementation was completed correctly.
Run:
1. `go build ./...`
2. `go vet ./...`
3. `go test ./pkg/robots/... -v`
4. Check that pkg/robots/robots.go exists
Write results to .ai/verify_robots.md.
Write status.json: outcome=success if ALL pass, outcome=fail with details."
]
check_robots [shape=diamond, label="Robots OK?"]
// Link checker implementation
impl_checker [
shape=box,
class="hard",
max_retries=2,
prompt="Goal: $goal
Spec: .ai/spec.md, link checker section.
Read: pkg/crawler/crawler.go, pkg/robots/robots.go for types.
Implement HTTP status checker in pkg/checker/:
- CheckLink function (HEAD or GET request, return status code)
- Categorize status codes (2xx=OK, 3xx=redirect, 4xx/5xx=broken)
- Timeout and retry handling
- Report struct with URL, status, error message
- Tests with mock HTTP server
Create/modify:
- pkg/checker/checker.go
- pkg/checker/status.go
- pkg/checker/checker_test.go
Acceptance:
- `go build ./...` must pass
- `go test ./pkg/checker/...` must pass
Write status.json: outcome=success if all criteria pass, outcome=fail with failure_reason otherwise."
]
verify_checker [
shape=box,
class="verify",
prompt="Verify link checker implementation was completed correctly.
Run:
1. `go build ./...`
2. `go vet ./...`
3. `go test ./pkg/checker/... -v`
4. Check that pkg/checker/checker.go exists
Write results to .ai/verify_checker.md.
Write status.json: outcome=success if ALL pass, outcome=fail with details."
]
check_checker [shape=diamond, label="Checker OK?"]
// Output formatter implementation
impl_formatter [
shape=box,
prompt="Goal: $goal
Spec: .ai/spec.md, output section.
Read: pkg/checker/checker.go for Report type.
Implement output formatters in pkg/formatter/:
- TextFormatter (human-readable table or list)
- JSONFormatter (structured JSON output)
- Format function that takes Report slice and format type
- Tests for both formatters
Create/modify:
- pkg/formatter/text.go
- pkg/formatter/json.go
- pkg/formatter/formatter.go
- pkg/formatter/formatter_test.go
Acceptance:
- `go build ./...` must pass
- `go test ./pkg/formatter/...` must pass
Write status.json: outcome=success if all criteria pass, outcome=fail with failure_reason otherwise."
]
verify_formatter [
shape=box,
class="verify",
prompt="Verify formatter implementation was completed correctly.
Run:
1. `go build ./...`
2. `go vet ./...`
3. `go test ./pkg/formatter/... -v`
4. Check that both text.go and json.go exist
Write results to .ai/verify_formatter.md.
Write status.json: outcome=success if ALL pass, outcome=fail with details."
]
check_formatter [shape=diamond, label="Formatter OK?"]
// CLI integration
impl_cli [
shape=box,
prompt="Goal: $goal
Spec: .ai/spec.md, CLI section.
Read: pkg/crawler/, pkg/robots/, pkg/checker/, pkg/formatter/ for all functions.
Wire up the CLI in cmd/linkcheck/main.go:
- Parse flags: --depth (default 1), --format (text/json), --user-agent
- Parse URL argument
- Orchestrate: check robots.txt, crawl, check links, format output
- Exit codes: 0 if no broken links, 1 if broken links found, 2 on error
- Help text
Acceptance:
- `go build ./cmd/linkcheck` must pass
- `./linkcheck --help` shows usage
- `./linkcheck https://example.com` runs without error
Write status.json: outcome=success if all criteria pass, outcome=fail with failure_reason otherwise."
]
verify_cli [
shape=box,
class="verify",
prompt="Verify CLI integration was completed correctly.
Run:
1. `go build ./cmd/linkcheck`
2. `./linkcheck --help` (must show help)
3. `go vet ./...`
4. Check that main.go wires all packages together
Write results to .ai/verify_cli.md.
Write status.json: outcome=success if ALL pass, outcome=fail with details."
]
check_cli [shape=diamond, label="CLI OK?"]
// Integration test
impl_integration [
shape=box,
goal_gate=true,
prompt="Goal: $goal
Spec: .ai/spec.md, test plan section.
Create integration test:
- Test script or test/integration_test.go
- Test with real HTTP calls (or mock server)
- Test depth=1 vs depth=2
- Test text vs JSON output
- Test robots.txt respect
Acceptance:
- `go build ./...` must pass
- `go test ./...` must pass (all tests)
- Integration test validates end-to-end functionality
Write status.json: outcome=success if all criteria pass, outcome=fail with failure_reason otherwise."
]
verify_integration [
shape=box,
class="verify",
prompt="Verify integration test was completed correctly.
Run:
1. `go build ./...`
2. `go test ./... -v`
3. Check that integration test covers depth, format, robots.txt
Write results to .ai/verify_integration.md.
Write status.json: outcome=success if ALL pass, outcome=fail with details."
]
check_integration [shape=diamond, label="Integration OK?"]
// Final review
review [
shape=box,
class="review",
goal_gate=true,
prompt="Goal: $goal
Read .ai/spec.md. Review the full linkcheck implementation against the spec.
Check:
- All features implemented (crawling, link checking, robots.txt, depth, formats)
- All tests pass
- CLI works as specified
- Error handling is correct
- Code quality (no warnings, good structure)
- Documentation complete
Run:
1. `go build ./cmd/linkcheck`
2. `go test ./...`
3. Manual test: `./linkcheck https://example.com --depth 1 --format json`
Write review to .ai/final_review.md.
Write status.json: outcome=success if complete and correct, outcome=fail with what's missing or broken."
]
check_review [shape=diamond, label="Review OK?"]
// Flow
start -> expand_spec -> impl_setup -> verify_setup -> check_setup
check_setup -> impl_crawler [condition="outcome=success"]
check_setup -> impl_setup [condition="outcome=fail", label="retry"]
impl_crawler -> verify_crawler -> check_crawler
check_crawler -> impl_robots [condition="outcome=success"]
check_crawler -> impl_crawler [condition="outcome=fail", label="retry"]
impl_robots -> verify_robots -> check_robots
check_robots -> impl_checker [condition="outcome=success"]
check_robots -> impl_robots [condition="outcome=fail", label="retry"]
impl_checker -> verify_checker -> check_checker
check_checker -> impl_formatter [condition="outcome=success"]
check_checker -> impl_checker [condition="outcome=fail", label="retry"]
impl_formatter -> verify_formatter -> check_formatter
check_formatter -> impl_cli [condition="outcome=success"]
check_formatter -> impl_formatter [condition="outcome=fail", label="retry"]
impl_cli -> verify_cli -> check_cli
check_cli -> impl_integration [condition="outcome=success"]
check_cli -> impl_cli [condition="outcome=fail", label="retry"]
impl_integration -> verify_integration -> check_integration
check_integration -> review [condition="outcome=success"]
check_integration -> impl_integration [condition="outcome=fail", label="retry"]
review -> check_review
check_review -> exit [condition="outcome=success"]
check_review -> impl_integration [condition="outcome=fail", label="fix"]
}