evilution 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.beads/.gitignore +51 -0
  3. data/.beads/.migration-hint-ts +1 -0
  4. data/.beads/README.md +81 -0
  5. data/.beads/config.yaml +67 -0
  6. data/.beads/interactions.jsonl +0 -0
  7. data/.beads/issues.jsonl +68 -0
  8. data/.beads/metadata.json +4 -0
  9. data/.claude/prompts/architect.md +98 -0
  10. data/.claude/prompts/devops.md +106 -0
  11. data/.claude/prompts/tests.md +160 -0
  12. data/CHANGELOG.md +19 -0
  13. data/CODE_OF_CONDUCT.md +10 -0
  14. data/LICENSE.txt +21 -0
  15. data/README.md +190 -0
  16. data/Rakefile +12 -0
  17. data/claude-swarm.yml +28 -0
  18. data/exe/evilution +6 -0
  19. data/lib/evilution/ast/parser.rb +83 -0
  20. data/lib/evilution/ast/source_surgeon.rb +13 -0
  21. data/lib/evilution/cli.rb +78 -0
  22. data/lib/evilution/config.rb +98 -0
  23. data/lib/evilution/coverage/collector.rb +47 -0
  24. data/lib/evilution/coverage/test_map.rb +25 -0
  25. data/lib/evilution/diff/file_filter.rb +29 -0
  26. data/lib/evilution/diff/parser.rb +47 -0
  27. data/lib/evilution/integration/base.rb +11 -0
  28. data/lib/evilution/integration/rspec.rb +184 -0
  29. data/lib/evilution/isolation/fork.rb +70 -0
  30. data/lib/evilution/mutation.rb +45 -0
  31. data/lib/evilution/mutator/base.rb +54 -0
  32. data/lib/evilution/mutator/operator/arithmetic_replacement.rb +37 -0
  33. data/lib/evilution/mutator/operator/array_literal.rb +22 -0
  34. data/lib/evilution/mutator/operator/boolean_literal_replacement.rb +31 -0
  35. data/lib/evilution/mutator/operator/boolean_operator_replacement.rb +50 -0
  36. data/lib/evilution/mutator/operator/collection_replacement.rb +37 -0
  37. data/lib/evilution/mutator/operator/comparison_replacement.rb +37 -0
  38. data/lib/evilution/mutator/operator/conditional_branch.rb +36 -0
  39. data/lib/evilution/mutator/operator/conditional_negation.rb +36 -0
  40. data/lib/evilution/mutator/operator/float_literal.rb +26 -0
  41. data/lib/evilution/mutator/operator/hash_literal.rb +22 -0
  42. data/lib/evilution/mutator/operator/integer_literal.rb +45 -0
  43. data/lib/evilution/mutator/operator/method_body_replacement.rb +22 -0
  44. data/lib/evilution/mutator/operator/negation_insertion.rb +22 -0
  45. data/lib/evilution/mutator/operator/nil_replacement.rb +20 -0
  46. data/lib/evilution/mutator/operator/return_value_removal.rb +22 -0
  47. data/lib/evilution/mutator/operator/statement_deletion.rb +24 -0
  48. data/lib/evilution/mutator/operator/string_literal.rb +22 -0
  49. data/lib/evilution/mutator/operator/symbol_literal.rb +20 -0
  50. data/lib/evilution/mutator/registry.rb +55 -0
  51. data/lib/evilution/parallel/pool.rb +98 -0
  52. data/lib/evilution/parallel/worker.rb +24 -0
  53. data/lib/evilution/reporter/cli.rb +72 -0
  54. data/lib/evilution/reporter/json.rb +59 -0
  55. data/lib/evilution/reporter/suggestion.rb +51 -0
  56. data/lib/evilution/result/mutation_result.rb +37 -0
  57. data/lib/evilution/result/summary.rb +54 -0
  58. data/lib/evilution/runner.rb +139 -0
  59. data/lib/evilution/subject.rb +20 -0
  60. data/lib/evilution/version.rb +5 -0
  61. data/lib/evilution.rb +51 -0
  62. data/sig/evilution.rbs +4 -0
  63. metadata +130 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 34fdc4c7cf9abac2c71dc0aa7d1aa4e4452e6237b8f1564c2dd92db2f5746cf5
4
+ data.tar.gz: 6d7bb8ef692815bbc62d8ca2a3446ee642bdc2c1834856064a48e4c311256b63
5
+ SHA512:
6
+ metadata.gz: 9f08ab9b14a0b43e26a15e499d65ce819f5443efa77311ff45bccf3ae230b3f4fc61bc1d20cf4beb464b6c70ca82964a21a5f8d889edb30b5ab2f18f8af3ca44
7
+ data.tar.gz: 84ba0567669d197cc56a2723a5e0fdeca84cf2b74085b5a273d9d7279211d156397ae520e7986fba81562393d25e21e3c99a1b6626cf472f79eeae11fede48ba
data/.beads/.gitignore ADDED
@@ -0,0 +1,51 @@
1
+ # SQLite databases
2
+ *.db
3
+ *.db?*
4
+ *.db-journal
5
+ *.db-wal
6
+ *.db-shm
7
+
8
+ # Daemon runtime files
9
+ daemon.lock
10
+ daemon.log
11
+ daemon-*.log.gz
12
+ daemon.pid
13
+ bd.sock
14
+ sync-state.json
15
+ last-touched
16
+
17
+ # Local version tracking (prevents upgrade notification spam after git ops)
18
+ .local_version
19
+
20
+ # Legacy database files
21
+ db.sqlite
22
+ bd.db
23
+
24
+ # Worktree redirect file (contains relative path to main repo's .beads/)
25
+ # Must not be committed as paths would be wrong in other clones
26
+ redirect
27
+
28
+ # Merge artifacts (temporary files from 3-way merge)
29
+ beads.base.jsonl
30
+ beads.base.meta.json
31
+ beads.left.jsonl
32
+ beads.left.meta.json
33
+ beads.right.jsonl
34
+ beads.right.meta.json
35
+
36
+ # Sync state (local-only, per-machine)
37
+ # These files are machine-specific and should not be shared across clones
38
+ .sync.lock
39
+ .jsonl.lock
40
+ sync_base.jsonl
41
+ export-state/
42
+
43
+ # Dolt database (managed by Dolt remotes, not git)
44
+ dolt/
45
+ dolt-access.lock
46
+
47
+ # NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here.
48
+ # They would override fork protection in .git/info/exclude, allowing
49
+ # contributors to accidentally commit upstream issue databases.
50
+ # The JSONL files (issues.jsonl, interactions.jsonl) and config files
51
+ # are tracked by git by default since no pattern above ignores them.
@@ -0,0 +1 @@
1
+ 1772686671
data/.beads/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # Beads - AI-Native Issue Tracking
2
+
3
+ Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
4
+
5
+ ## What is Beads?
6
+
7
+ Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
8
+
9
+ **Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
10
+
11
+ ## Quick Start
12
+
13
+ ### Essential Commands
14
+
15
+ ```bash
16
+ # Create new issues
17
+ bd create "Add user authentication"
18
+
19
+ # View all issues
20
+ bd list
21
+
22
+ # View issue details
23
+ bd show <issue-id>
24
+
25
+ # Update issue status
26
+ bd update <issue-id> --status in_progress
27
+ bd update <issue-id> --status done
28
+
29
+ # Sync with git remote
30
+ bd sync
31
+ ```
32
+
33
+ ### Working with Issues
34
+
35
+ Issues in Beads are:
36
+ - **Git-native**: Stored in `.beads/issues.jsonl` and synced like code
37
+ - **AI-friendly**: CLI-first design works perfectly with AI coding agents
38
+ - **Branch-aware**: Issues can follow your branch workflow
39
+ - **Always in sync**: Auto-syncs with your commits
40
+
41
+ ## Why Beads?
42
+
43
+ ✨ **AI-Native Design**
44
+ - Built specifically for AI-assisted development workflows
45
+ - CLI-first interface works seamlessly with AI coding agents
46
+ - No context switching to web UIs
47
+
48
+ 🚀 **Developer Focused**
49
+ - Issues live in your repo, right next to your code
50
+ - Works offline, syncs when you push
51
+ - Fast, lightweight, and stays out of your way
52
+
53
+ 🔧 **Git Integration**
54
+ - Automatic sync with git commits
55
+ - Branch-aware issue tracking
56
+ - Intelligent JSONL merge resolution
57
+
58
+ ## Get Started with Beads
59
+
60
+ Try Beads in your own projects:
61
+
62
+ ```bash
63
+ # Install Beads
64
+ curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
65
+
66
+ # Initialize in your repo
67
+ bd init
68
+
69
+ # Create your first issue
70
+ bd create "Try out Beads"
71
+ ```
72
+
73
+ ## Learn More
74
+
75
+ - **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
76
+ - **Quick Start Guide**: Run `bd quickstart`
77
+ - **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
78
+
79
+ ---
80
+
81
+ *Beads: Issue tracking that moves at the speed of thought* ⚡
@@ -0,0 +1,67 @@
1
+ # Beads Configuration File
2
+ # This file configures default behavior for all bd commands in this repository
3
+ # All settings can also be set via environment variables (BD_* prefix)
4
+ # or overridden with command-line flags
5
+
6
+ # Issue prefix for this repository (used by bd init)
7
+ # If not set, bd init will auto-detect from directory name
8
+ # Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
9
+ issue-prefix: "EV"
10
+
11
+ # Use no-db mode: load from JSONL, no SQLite, write back after each command
12
+ # When true, bd will use .beads/issues.jsonl as the source of truth
13
+ # instead of SQLite database
14
+ no-db: true # JSONL-only mode, no SQLite database
15
+
16
+ # Disable daemon for RPC communication (forces direct database access)
17
+ # no-daemon: false
18
+
19
+ # Disable auto-flush of database to JSONL after mutations
20
+ # no-auto-flush: false
21
+
22
+ # Disable auto-import from JSONL when it's newer than database
23
+ # no-auto-import: false
24
+
25
+ # Enable JSON output by default
26
+ # json: false
27
+
28
+ # Default actor for audit trails (overridden by BD_ACTOR or --actor)
29
+ # actor: ""
30
+
31
+ # Path to database (overridden by BEADS_DB or --db)
32
+ # db: ""
33
+
34
+ # Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON)
35
+ # auto-start-daemon: true
36
+
37
+ # Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE)
38
+ # flush-debounce: "5s"
39
+
40
+ # Export events (audit trail) to .beads/events.jsonl on each flush/sync
41
+ # When enabled, new events are appended incrementally using a high-water mark.
42
+ # Use 'bd export --events' to trigger manually regardless of this setting.
43
+ # events-export: false
44
+
45
+ # Git branch for beads commits (bd sync will commit to this branch)
46
+ # IMPORTANT: Set this for team projects so all clones use the same sync branch.
47
+ # This setting persists across clones (unlike database config which is gitignored).
48
+ # Can also use BEADS_SYNC_BRANCH env var for local override.
49
+ # If not set, bd sync will require you to run 'bd config set sync.branch <branch>'.
50
+ # sync-branch: "beads-sync"
51
+
52
+ # Multi-repo configuration (experimental - bd-307)
53
+ # Allows hydrating from multiple repositories and routing writes to the correct JSONL
54
+ # repos:
55
+ # primary: "." # Primary repo (where this database lives)
56
+ # additional: # Additional repos to hydrate from (read-only)
57
+ # - ~/beads-planning # Personal planning repo
58
+ # - ~/work-planning # Work planning repo
59
+
60
+ # Integration settings (access with 'bd config get/set')
61
+ # These are stored in the database, not in this file:
62
+ # - jira.url
63
+ # - jira.project
64
+ # - linear.url
65
+ # - linear.api-key
66
+ # - github.org
67
+ # - github.repo
File without changes
@@ -0,0 +1,68 @@
1
+ {"id":"EV-1","title":"Agent Prompts & Project Setup","description":"Update all specialist agent prompts for mutation testing gem context, clean up swarm config, update gemspec","status":"closed","priority":2,"issue_type":"epic","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:04:56.523776106+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:42:03.57981105+07:00","closed_at":"2026-03-02T10:42:03.57981105+07:00","close_reason":"Closed"}
2
+ {"id":"EV-1.1","title":"Rewrite architect.md prompt for mutation testing gem","description":"Remove all Rails references (Devise, Pundit, credentials). Rewrite as Ruby gem architect: Prism AST, fork isolation, minimal deps. Team: Tests + DevOps only. Principles: TDD, AI-agent-first, zero dead code.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:17.321892372+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:39:38.702908998+07:00","closed_at":"2026-03-02T10:39:38.702908998+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-1.1","depends_on_id":"EV-1","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
3
+ {"id":"EV-1.2","title":"Rewrite tests.md prompt for gem testing","description":"Remove Rails/Capybara/FactoryBot/Shoulda/Pundit/SimpleCov. Rewrite for gem RSpec testing: unit specs per class, integration specs for pipeline, fixture Ruby files for parser testing, mutation operator boundary tests.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:17.429986782+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:40:24.130210342+07:00","closed_at":"2026-03-02T10:40:24.130210342+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-1.2","depends_on_id":"EV-1","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
4
+ {"id":"EV-1.3","title":"Rewrite devops.md prompt for gem CI/CD","description":"Remove Docker/Postgres/Redis/Puma/Sidekiq/Rails. Rewrite for gem CI: GitHub Actions multi-Ruby matrix (3.2, 3.3, 4.0), RubyGems publishing, gem versioning, bundler audit, rubocop.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:17.536909853+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:40:57.402172824+07:00","closed_at":"2026-03-02T10:40:57.402172824+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-1.3","depends_on_id":"EV-1","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
5
+ {"id":"EV-1.4","title":"Delete services.md prompt","description":"Remove .claude/prompts/services.md — not applicable to a gem project.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:17.649482526+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:41:19.226636126+07:00","closed_at":"2026-03-02T10:41:19.226636126+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-1.4","depends_on_id":"EV-1","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
6
+ {"id":"EV-1.5","title":"Update gemspec metadata","description":"Fill in summary, description, homepage, source_code_uri, changelog_uri. Add runtime dependency: diff-lcs (>= 1.5, < 3). Set allowed_push_host to rubygems.org.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:17.756448433+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:41:47.168270415+07:00","closed_at":"2026-03-02T10:41:47.168270415+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-1.5","depends_on_id":"EV-1","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
7
+ {"id":"EV-1.6","title":"Update .rubocop.yml for gem conventions","description":"Configure rubocop for gem: enable NewCops, set reasonable line length, exclude spec fixtures.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:17.855784448+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:42:03.456572349+07:00","closed_at":"2026-03-02T10:42:03.456572349+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-1.6","depends_on_id":"EV-1","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
8
+ {"id":"EV-10","title":"Publish v0.1.0 gem release","description":"Gemspec is ready. Tag v0.1.0, build the gem, and publish to RubyGems. Steps: verify gemspec metadata, run rake release (or manual gem build + gem push), create GitHub release with CHANGELOG notes.","status":"open","priority":3,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T16:21:53.571182801+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T16:21:53.571182801+07:00"}
9
+ {"id":"EV-11","title":"Wire coverage-based filtering into Runner","description":"Collector and TestMap exist and pass specs, but Runner never calls them. When config.coverage is true, Runner collects aggregate line-level coverage via Coverage::Collector, builds a Coverage::TestMap, and skips mutations on lines that no test exercises (marking them as survived with zero duration). Note: Ruby Coverage provides aggregate per-file line hit counts, not per-test-file tracking, so we filter out uncovered mutations rather than selecting specific test files.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-04T11:52:42.607616728+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-06T11:02:25.4848637+07:00","closed_at":"2026-03-05T14:53:24.894588088+07:00","close_reason":"Coverage-based test selection wired into Runner"}
10
+ {"id":"EV-12","title":"Resolve suggestion gap","description":"The workflow section instructs agents to read a suggestion field from survived[], but the JSON reporter output does not include suggestion (lib/evilution/reporter/json.rb only emits operator/file/line/status/duration/diff). Either add suggestion to the JSON output/schema or update the workflow steps to match the actual report fields. See GitHub issue #12.","status":"closed","priority":2,"issue_type":"bug","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-05T12:33:23.674094791+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-05T13:05:48.785616141+07:00","closed_at":"2026-03-05T13:05:48.785616141+07:00","close_reason":"Wired Suggestion into JSON reporter for survived mutations, updated README schema, added specs"}
11
+ {"id":"EV-13","title":"Enable true per-mutation isolation with temp file copies","description":"Replace direct file writes with temp-dir + $LOAD_PATH isolation so multiple workers can mutate the same file in parallel. Remove per-file grouping from Pool#partition.","status":"closed","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-05T13:42:04.711580397+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-05T13:44:34.779951959+07:00","closed_at":"2026-03-05T13:44:34.779951959+07:00","close_reason":"Implemented temp file isolation via $LOAD_PATH and round-robin partition"}
12
+ {"id":"EV-2","title":"Phase 1: Foundation — End-to-End Single Mutation","description":"Build the core pipeline: parse Ruby with Prism, generate mutations, fork-based isolation, RSpec integration, JSON reporting. Milestone: Runner.new(files: ['lib/user.rb']).call produces JSON output.","status":"closed","priority":2,"issue_type":"epic","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:04:58.737191467+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:02:00.342745637+07:00","closed_at":"2026-03-02T11:02:00.342745637+07:00","close_reason":"Phase 1 Foundation complete: Config, AST::Parser, Subject, SourceSurgeon, Mutation, Mutator::Base+Registry, ComparisonReplacement, Isolation::Fork, Integration::RSpec, Result objects, Reporter::JSON, Runner — all 13 tasks done"}
13
+ {"id":"EV-2.1","title":"Implement Evilution::Config","description":"Immutable configuration value object. Fields: target_files, jobs (default: Etc.nprocessors), timeout (default: 10s), format (:json/:text), diff_base (nil), min_score (0.0), integration (:rspec), config_file path. Merge from defaults + YAML + CLI flags. File: lib/evilution/config.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:50.275297792+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:43:14.688620834+07:00","closed_at":"2026-03-02T10:43:14.688620834+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.1","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
14
+ {"id":"EV-2.10","title":"Implement Evilution::Integration::Base and RSpec adapter","description":"Base: abstract adapter with interface #call(test_files) -> {passed: bool, example_count: int, failure_count: int}. RSpec: programmatic runner using RSpec::Core::Runner.run with StringIO for capture. Auto-detects spec/ directory. Files: lib/evilution/integration/base.rb, lib/evilution/integration/rspec.rb + specs.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.246990324+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:58:18.324768622+07:00","closed_at":"2026-03-02T10:58:18.324768622+07:00","close_reason":"Integration::Base and Integration::RSpec implemented with 8 passing specs","dependencies":[{"issue_id":"EV-2.10","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
15
+ {"id":"EV-2.11","title":"Implement Evilution::Reporter::JSON","description":"JSON reporter outputting structured results for AI agents. Schema: version, timestamp, config, summary (total/killed/survived/score), subjects array, survived array (with file/line/operator/original/mutated/diff/suggestion), killed array, timed_out, errors. File: lib/evilution/reporter/json.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.346423018+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:59:26.038994933+07:00","closed_at":"2026-03-02T10:59:26.038994933+07:00","close_reason":"Reporter::JSON implemented with 8 passing specs","dependencies":[{"issue_id":"EV-2.11","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.11","depends_on_id":"EV-2.8","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
16
+ {"id":"EV-2.12","title":"Implement Evilution::Runner","description":"Main orchestrator wiring the full pipeline. Flow: load config -> parse target files (AST::Parser) -> extract subjects -> generate mutations (Registry) -> for each mutation: fork + run tests (Isolation::Fork + Integration::RSpec) -> collect results (Summary) -> output (Reporter). Method: #call -> Result::Summary. File: lib/evilution/runner.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.442413842+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:01:11.427106081+07:00","closed_at":"2026-03-02T11:01:11.427106081+07:00","close_reason":"Runner orchestrator implemented with 8 passing specs, wires full pipeline","dependencies":[{"issue_id":"EV-2.12","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.12","depends_on_id":"EV-2.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.12","depends_on_id":"EV-2.2","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.12","depends_on_id":"EV-2.7","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.12","depends_on_id":"EV-2.9","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.12","depends_on_id":"EV-2.10","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.12","depends_on_id":"EV-2.11","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
17
+ {"id":"EV-2.13","title":"Update lib/evilution.rb with proper requires","description":"Update root module file to require all Phase 1 components in correct dependency order. Remove placeholder comments. File: lib/evilution.rb.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.535207642+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:01:55.399136342+07:00","closed_at":"2026-03-02T11:01:55.399136342+07:00","close_reason":"Root evilution.rb now requires all Phase 1 components in dependency order","dependencies":[{"issue_id":"EV-2.13","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.13","depends_on_id":"EV-2.12","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
18
+ {"id":"EV-2.2","title":"Implement Evilution::AST::Parser","description":"Wrap Prism.parse to parse Ruby files. Extract DefNode instances as Subject candidates. Handle class/module nesting to build fully-qualified method names (e.g., User#adult?). File: lib/evilution/ast/parser.rb + spec with fixture Ruby files.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:50.377591457+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:45:08.284323205+07:00","closed_at":"2026-03-02T10:45:08.284323205+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.2","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
19
+ {"id":"EV-2.3","title":"Implement Evilution::Subject","description":"Value object representing one testable method. Fields: name (e.g., User#adult?), file_path, line_number, source (original source string), ast_node (Prism::DefNode). File: lib/evilution/subject.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:50.496471448+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:45:08.389509869+07:00","closed_at":"2026-03-02T10:45:08.389509869+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.3","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.3","depends_on_id":"EV-2.2","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
20
+ {"id":"EV-2.4","title":"Implement Evilution::AST::SourceSurgeon","description":"Performs text-level source mutations using Prism byte offsets. Method: apply(source_string, offset, length, replacement) -> mutated_string. Handles multi-byte chars correctly. File: lib/evilution/ast/source_surgeon.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:50.602911488+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:46:03.418299334+07:00","closed_at":"2026-03-02T10:46:03.418299334+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.4","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
21
+ {"id":"EV-2.5","title":"Implement Evilution::Mutation","description":"Value object representing one code change. Fields: subject, operator_name, original_source, mutated_source, file_path, line, column. Method: diff (returns unified diff string). File: lib/evilution/mutation.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:50.706572477+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:47:19.013666966+07:00","closed_at":"2026-03-02T10:47:19.013666966+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.5","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.5","depends_on_id":"EV-2.3","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.5","depends_on_id":"EV-2.4","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
22
+ {"id":"EV-2.6","title":"Implement Evilution::Mutator::Base and Registry","description":"Base: abstract class with interface #call(subject) -> [Mutation]. Uses Prism::Visitor to walk AST, subclasses override visit_* methods. Registry: maps Prism node types to operator classes, provides .mutations_for(subject) that runs all registered operators. Files: lib/evilution/mutator/base.rb, lib/evilution/mutator/registry.rb + specs.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:50.806207045+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:48:54.954279456+07:00","closed_at":"2026-03-02T10:48:54.954279456+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.6","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.6","depends_on_id":"EV-2.5","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
23
+ {"id":"EV-2.7","title":"Implement ComparisonReplacement operator","description":"First mutation operator. Targets CallNode where name is :>, :<, :>=, :<=, :==, :!=. Replacements: > -> [>=, ==], < -> [<=, ==], >= -> [>, ==], <= -> [<, ==], == -> [!=], != -> [==]. Uses SourceSurgeon to apply text replacement at message_loc offsets. File: lib/evilution/mutator/operator/comparison_replacement.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:50.917501278+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:50:01.327985674+07:00","closed_at":"2026-03-02T10:50:01.327985674+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.7","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.7","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.7","depends_on_id":"EV-2.4","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
24
+ {"id":"EV-2.8","title":"Implement Evilution::Result::MutationResult and Summary","description":"MutationResult: value object with fields: mutation, status (:killed/:survived/:timeout/:error), duration, killing_test (optional). Summary: aggregates MutationResult array into total/killed/survived/timed_out/errors/score/duration. Files: lib/evilution/result/mutation_result.rb, lib/evilution/result/summary.rb + specs.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.022249568+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:51:08.482621898+07:00","closed_at":"2026-03-02T10:51:08.482621898+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-2.8","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
25
+ {"id":"EV-2.9","title":"Implement Evilution::Isolation::Fork","description":"Fork-based process isolation. Method: run(mutation, test_command, timeout:) -> MutationResult. Flow: create pipe, fork child, child applies mutation via eval, child runs test command, marshal result back via pipe, parent reads with IO.select timeout, SIGKILL on deadline. File: lib/evilution/isolation/fork.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:51.142167275+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T10:54:08.819310594+07:00","closed_at":"2026-03-02T10:54:08.819310594+07:00","close_reason":"Fork isolation implemented with 6 passing specs","dependencies":[{"issue_id":"EV-2.9","depends_on_id":"EV-2","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-2.9","depends_on_id":"EV-2.8","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
26
+ {"id":"EV-3","title":"Phase 2: Mutation Operators & CLI","description":"Implement remaining 17 mutation operators, build CLI with OptionParser, exe/evilution executable, human-readable reporter. Milestone: bundle exec evilution run lib/user.rb --format json","status":"closed","priority":2,"issue_type":"epic","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:00.492971295+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:21:32.168384165+07:00","closed_at":"2026-03-02T11:21:32.168384165+07:00","close_reason":"Phase 2 complete: all 18 operators, CLI, Reporter::CLI, Registry registration, executable","dependencies":[{"issue_id":"EV-3","depends_on_id":"EV-2","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
27
+ {"id":"EV-3.1","title":"Implement ArithmeticReplacement operator","description":"Targets CallNode where name is :+, :-, :*, :/, :%, :**. Replacements: + <-> -, * <-> /, % -> /, ** -> *. File: lib/evilution/mutator/operator/arithmetic_replacement.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:13.025649082+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:06:10.922412304+07:00","closed_at":"2026-03-02T11:06:10.922412304+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.1","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.1","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
28
+ {"id":"EV-3.10","title":"Implement SymbolLiteral operator","description":"Targets SymbolNode. Mutation: :foo -> :__evilution_mutated__. File: lib/evilution/mutator/operator/symbol_literal.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:13.935877816+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:13:36.541040613+07:00","closed_at":"2026-03-02T11:13:36.541040613+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.10","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.10","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
29
+ {"id":"EV-3.11","title":"Implement ConditionalNegation operator","description":"Targets IfNode and UnlessNode. Mutations: replace predicate with true, replace predicate with false. File: lib/evilution/mutator/operator/conditional_negation.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:14.035939305+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:13:36.541102748+07:00","closed_at":"2026-03-02T11:13:36.541102748+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.11","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.11","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
30
+ {"id":"EV-3.12","title":"Implement ConditionalBranch operator","description":"Targets IfNode with both if and else branches. Mutations: replace entire if/else with if-branch only, replace with else-branch only. File: lib/evilution/mutator/operator/conditional_branch.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:14.138508575+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:13:36.541106251+07:00","closed_at":"2026-03-02T11:13:36.541106251+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.12","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.12","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
31
+ {"id":"EV-3.13","title":"Implement StatementDeletion operator","description":"Targets StatementsNode bodies with 2+ statements. For each statement, produce a mutation that removes it. File: lib/evilution/mutator/operator/statement_deletion.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:14.240151154+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:16:08.954716442+07:00","closed_at":"2026-03-02T11:16:08.954716442+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.13","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.13","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
32
+ {"id":"EV-3.14","title":"Implement MethodBodyReplacement operator","description":"Targets DefNode with body. Mutations: replace body with nil, replace with raise NotImplementedError. File: lib/evilution/mutator/operator/method_body_replacement.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:14.333934644+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:16:08.954887847+07:00","closed_at":"2026-03-02T11:16:08.954887847+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.14","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.14","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
33
+ {"id":"EV-3.15","title":"Implement NegationInsertion operator","description":"Targets CallNode with predicate method names (ending in ?). Mutation: x.empty? -> !x.empty?. File: lib/evilution/mutator/operator/negation_insertion.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:14.438532333+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:16:08.95490096+07:00","closed_at":"2026-03-02T11:16:08.95490096+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.15","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.15","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
34
+ {"id":"EV-3.16","title":"Implement ReturnValueRemoval operator","description":"Targets ReturnNode with arguments. Mutations: return x -> return, return x -> return nil. File: lib/evilution/mutator/operator/return_value_removal.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:14.541333631+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:18:14.396683739+07:00","closed_at":"2026-03-02T11:18:14.396683739+07:00","close_reason":"Both operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.16","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.16","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
35
+ {"id":"EV-3.17","title":"Implement CollectionReplacement operator","description":"Targets CallNode where name matches collection methods. Replacements: map->each, select<->reject, all?<->any?, first<->last, min<->max, flat_map->map. File: lib/evilution/mutator/operator/collection_replacement.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:14.635444378+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:18:14.396880048+07:00","closed_at":"2026-03-02T11:18:14.396880048+07:00","close_reason":"Both operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.17","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.17","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
36
+ {"id":"EV-3.18","title":"Implement Evilution::CLI","description":"OptionParser-based CLI. Commands: run [FILES...], version, init. Flags: --jobs/-j, --timeout/-t, --format/-f (json/text), --diff BASE, --target PATTERN, --min-score FLOAT, --no-coverage, --config FILE, --verbose/-v, --quiet/-q. Parses args into Config, delegates to Runner. File: lib/evilution/cli.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:26.540459363+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:20:50.084035782+07:00","closed_at":"2026-03-02T11:20:50.084035782+07:00","close_reason":"CLI, Reporter::CLI, and Registry registration all implemented","dependencies":[{"issue_id":"EV-3.18","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.18","depends_on_id":"EV-2.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.18","depends_on_id":"EV-2.12","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
37
+ {"id":"EV-3.19","title":"Create exe/evilution executable","description":"Executable entry point at exe/evilution. Requires evilution/cli, calls Evilution::CLI.new(ARGV).call. Set chmod +x. Verify gemspec bindir=exe and executables include it.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:26.649421905+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:21:32.057434126+07:00","closed_at":"2026-03-02T11:21:32.057434126+07:00","close_reason":"exe/evilution created and working","dependencies":[{"issue_id":"EV-3.19","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.19","depends_on_id":"EV-3.18","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
38
+ {"id":"EV-3.2","title":"Implement BooleanOperatorReplacement operator","description":"Targets AndNode (&&) and OrNode (||). Replacement: && <-> ||. Uses operator_loc for text replacement. File: lib/evilution/mutator/operator/boolean_operator_replacement.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:13.130261533+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:06:10.922468277+07:00","closed_at":"2026-03-02T11:06:10.922468277+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.2","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.2","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
39
+ {"id":"EV-3.20","title":"Implement Evilution::Reporter::CLI","description":"Human-readable terminal reporter. Shows: header with version, target summary, progress indicator, per-subject results (killed/total), survived mutant details with suggestions, summary line with score, exit code hint. File: lib/evilution/reporter/cli.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:26.751170027+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:20:50.084126714+07:00","closed_at":"2026-03-02T11:20:50.084126714+07:00","close_reason":"CLI, Reporter::CLI, and Registry registration all implemented","dependencies":[{"issue_id":"EV-3.20","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.20","depends_on_id":"EV-2.8","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
40
+ {"id":"EV-3.21","title":"Register all 18 operators in Registry","description":"Update Mutator::Registry to register all 18 operator classes. Ensure require order is correct in lib/evilution.rb. Verify all operators are discovered and run for appropriate AST node types. Integration test with a fixture file that exercises all operator categories.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:26.855255932+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:20:50.084132113+07:00","closed_at":"2026-03-02T11:20:50.084132113+07:00","close_reason":"CLI, Reporter::CLI, and Registry registration all implemented","dependencies":[{"issue_id":"EV-3.21","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-2.7","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.2","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.3","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.4","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.5","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.7","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.8","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.9","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.10","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.11","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.12","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.13","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.14","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.15","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.16","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.21","depends_on_id":"EV-3.17","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
41
+ {"id":"EV-3.3","title":"Implement BooleanLiteralReplacement operator","description":"Targets TrueNode and FalseNode. Replacement: true <-> false. File: lib/evilution/mutator/operator/boolean_literal_replacement.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:13.234832031+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:06:10.922472056+07:00","closed_at":"2026-03-02T11:06:10.922472056+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.3","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.3","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
42
+ {"id":"EV-3.4","title":"Implement NilReplacement operator","description":"Targets expressions in return/assignment contexts. Replacement: expr -> nil. File: lib/evilution/mutator/operator/nil_replacement.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:13.341191161+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:08:21.298853786+07:00","closed_at":"2026-03-02T11:08:21.298853786+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.4","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.4","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
43
+ {"id":"EV-3.5","title":"Implement IntegerLiteral operator","description":"Targets IntegerNode. Mutations: n -> 0, 1, n+1, n-1 (skip if already 0 or 1). File: lib/evilution/mutator/operator/integer_literal.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:13.43928023+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:08:21.298976207+07:00","closed_at":"2026-03-02T11:08:21.298976207+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.5","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.5","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
44
+ {"id":"EV-3.6","title":"Implement FloatLiteral operator","description":"Targets FloatNode. Mutations: f -> 0.0, 1.0. File: lib/evilution/mutator/operator/float_literal.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:13.533556264+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:08:21.298985394+07:00","closed_at":"2026-03-02T11:08:21.298985394+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.6","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.6","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
45
+ {"id":"EV-3.7","title":"Implement StringLiteral operator","description":"Targets StringNode. Mutations: non-empty -> empty string, empty -> 'mutation'. File: lib/evilution/mutator/operator/string_literal.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:13.633726423+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:10:56.39748015+07:00","closed_at":"2026-03-02T11:10:56.39748015+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.7","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.7","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
46
+ {"id":"EV-3.8","title":"Implement ArrayLiteral operator","description":"Targets ArrayNode with elements. Mutation: [a, b, c] -> []. File: lib/evilution/mutator/operator/array_literal.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:13.734617709+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:10:56.397565925+07:00","closed_at":"2026-03-02T11:10:56.397565925+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.8","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.8","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
47
+ {"id":"EV-3.9","title":"Implement HashLiteral operator","description":"Targets HashNode with pairs. Mutation: {k: v} -> {}. File: lib/evilution/mutator/operator/hash_literal.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:13.840779748+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:10:56.397570989+07:00","closed_at":"2026-03-02T11:10:56.397570989+07:00","close_reason":"All 3 operators implemented with passing specs","dependencies":[{"issue_id":"EV-3.9","depends_on_id":"EV-3","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-3.9","depends_on_id":"EV-2.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
48
+ {"id":"EV-4","title":"Phase 3: Performance Features","description":"Parallel execution pool, coverage-based mutation filtering, git diff-based targeting. Milestone: evilution run --diff HEAD~1 --jobs 4","status":"closed","priority":2,"issue_type":"epic","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:02.252877807+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-06T11:02:29.997677574+07:00","closed_at":"2026-03-02T11:54:32.782829837+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-4","depends_on_id":"EV-3","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
49
+ {"id":"EV-4.1","title":"Implement Evilution::Parallel::Pool","description":"Thread-based worker pool distributing fork workers. Initialize with job_count. Method: #run(mutations, test_command, timeout:) -> [MutationResult]. Uses Queue to distribute work to N threads, each thread calls Isolation::Fork. File: lib/evilution/parallel/pool.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:44.984077473+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:46:46.640997276+07:00","closed_at":"2026-03-02T11:46:46.640997276+07:00","close_reason":"Pool implementation and tests already exist and pass","dependencies":[{"issue_id":"EV-4.1","depends_on_id":"EV-4","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.1","depends_on_id":"EV-2.9","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
50
+ {"id":"EV-4.2","title":"Implement Evilution::Parallel::Worker","description":"Individual worker abstraction managing fork lifecycle. Wraps Isolation::Fork with queue consumption loop. File: lib/evilution/parallel/worker.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:45.08570827+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:21.51846223+07:00","closed_at":"2026-03-02T11:54:21.51846223+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-4.2","depends_on_id":"EV-4","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.2","depends_on_id":"EV-4.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
51
+ {"id":"EV-4.3","title":"Implement Evilution::Coverage::Collector","description":"Wraps Ruby's Coverage module. Method: #collect { block } -> coverage_data. Calls Coverage.start(lines: true), yields block (run test suite), calls Coverage.result. Returns hash of {file_path => {lines: [counts]}}. File: lib/evilution/coverage/collector.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:45.193649937+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:46:46.741089672+07:00","closed_at":"2026-03-02T11:46:46.741089672+07:00","close_reason":"Collector implementation and tests already exist and pass","dependencies":[{"issue_id":"EV-4.3","depends_on_id":"EV-4","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
52
+ {"id":"EV-4.4","title":"Implement Evilution::Coverage::TestMap","description":"Maps source lines to relevant test files. Method: #tests_for(file_path, line) -> [spec_file_paths]. MVP: file-level granularity (any spec that touches the file). File: lib/evilution/coverage/test_map.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:45.311522252+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:46:46.849128681+07:00","closed_at":"2026-03-02T11:46:46.849128681+07:00","close_reason":"TestMap implementation and tests already exist and pass","dependencies":[{"issue_id":"EV-4.4","depends_on_id":"EV-4","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.4","depends_on_id":"EV-4.3","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
53
+ {"id":"EV-4.5","title":"Implement Evilution::Diff::Parser","description":"Parses git diff output to extract changed file paths and line ranges. Method: #parse(diff_base) -> [{file: path, lines: [Range]}]. Calls git diff --unified=0 BASE..HEAD. File: lib/evilution/diff/parser.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:45.416920415+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:21.518321159+07:00","closed_at":"2026-03-02T11:54:21.518321159+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-4.5","depends_on_id":"EV-4","type":"parent-child","created_at":"0001-01-01T00:00:00Z"}]}
54
+ {"id":"EV-4.6","title":"Implement Evilution::Diff::FileFilter","description":"Filters Subject array to only subjects whose methods overlap with changed lines from Diff::Parser. Method: #filter(subjects, changed_ranges) -> [Subject]. File: lib/evilution/diff/file_filter.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:45.523694432+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:25.596217122+07:00","closed_at":"2026-03-02T11:54:25.596217122+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-4.6","depends_on_id":"EV-4","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.6","depends_on_id":"EV-4.5","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.6","depends_on_id":"EV-2.3","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
55
+ {"id":"EV-4.7","title":"Integrate parallel execution into Runner","description":"Update Runner to use Parallel::Pool when jobs > 1. Replace sequential mutation execution with pool.run. Verify results are identical. File: lib/evilution/runner.rb (edit).","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:45.637953763+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:25.596270941+07:00","closed_at":"2026-03-02T11:54:25.596270941+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-4.7","depends_on_id":"EV-4","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.7","depends_on_id":"EV-4.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.7","depends_on_id":"EV-2.12","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
56
+ {"id":"EV-4.8","title":"Integrate coverage-based filtering into Runner","description":"Update Runner to optionally collect coverage on first test suite run, build TestMap, and skip mutations on uncovered lines. Controlled by --no-coverage flag. File: lib/evilution/runner.rb (edit).","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:45.745583233+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-06T11:02:35.638752306+07:00","closed_at":"2026-03-02T11:54:25.596274893+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-4.8","depends_on_id":"EV-4","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.8","depends_on_id":"EV-4.4","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.8","depends_on_id":"EV-2.12","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
57
+ {"id":"EV-4.9","title":"Integrate diff-based targeting into Runner","description":"Update Runner to optionally use Diff::Parser + FileFilter when --diff flag is set. Filter subjects before mutation generation. File: lib/evilution/runner.rb (edit).","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:45.851982561+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:25.596280246+07:00","closed_at":"2026-03-02T11:54:25.596280246+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-4.9","depends_on_id":"EV-4","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.9","depends_on_id":"EV-4.6","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-4.9","depends_on_id":"EV-2.12","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
58
+ {"id":"EV-5","title":"Phase 4: Polish","description":"Suggestion generator, .evilution.yml config file loading, evilution init subcommand, error handling, README","status":"closed","priority":2,"issue_type":"epic","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:05:03.497091872+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:32.782883746+07:00","closed_at":"2026-03-02T11:54:32.782883746+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-5","depends_on_id":"EV-4","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
59
+ {"id":"EV-5.1","title":"Implement Evilution::Reporter::Suggestion","description":"Generates actionable fix suggestions per surviving mutant. Each operator type has a suggestion template. E.g., ComparisonReplacement >= -> > suggests 'Add a test for the boundary case where value equals exactly [threshold]'. File: lib/evilution/reporter/suggestion.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:58.038411009+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:21.518470747+07:00","closed_at":"2026-03-02T11:54:21.518470747+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-5.1","depends_on_id":"EV-5","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-5.1","depends_on_id":"EV-2.8","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-5.1","depends_on_id":"EV-3.21","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
60
+ {"id":"EV-5.2","title":"Implement .evilution.yml config file loading","description":"Load config from .evilution.yml / config/evilution.yml if present. YAML keys map to Config fields. CLI flags override file values. File: update lib/evilution/config.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:58.142538793+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:21.518473527+07:00","closed_at":"2026-03-02T11:54:21.518473527+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-5.2","depends_on_id":"EV-5","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-5.2","depends_on_id":"EV-2.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
61
+ {"id":"EV-5.3","title":"Implement evilution init subcommand","description":"CLI subcommand that generates a default .evilution.yml with commented-out options and sensible defaults. File: update lib/evilution/cli.rb + spec.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:58.246160804+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:25.59628257+07:00","closed_at":"2026-03-02T11:54:25.59628257+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-5.3","depends_on_id":"EV-5","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-5.3","depends_on_id":"EV-3.18","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
62
+ {"id":"EV-5.4","title":"Add error handling and edge cases","description":"Handle: no test files found, no subjects found, fork failures, marshal errors, invalid config, files that fail to parse. Use Evilution::Error subclasses. Ensure clean exit codes (2 for tool errors).","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:58.353265504+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:25.59628785+07:00","closed_at":"2026-03-02T11:54:25.59628785+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-5.4","depends_on_id":"EV-5","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-5.4","depends_on_id":"EV-2.12","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
63
+ {"id":"EV-5.5","title":"Write README.md","description":"Replace placeholder README with: gem description, installation, quick start, CLI usage, configuration, output formats (JSON schema), operator list, comparison with mutant, contributing guide, license.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:58.454635118+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:29.226280116+07:00","closed_at":"2026-03-02T11:54:29.226280116+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-5.5","depends_on_id":"EV-5","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-5.5","depends_on_id":"EV-4.9","type":"blocks","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-5.5","depends_on_id":"EV-5.1","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
64
+ {"id":"EV-5.6","title":"Update CHANGELOG.md for v0.1.0","description":"Document all features in the initial release: operator list, RSpec integration, JSON/CLI output, parallel execution, coverage-based selection, diff-based targeting.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T00:06:58.571499415+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T11:54:29.22634981+07:00","closed_at":"2026-03-02T11:54:29.22634981+07:00","close_reason":"Closed","dependencies":[{"issue_id":"EV-5.6","depends_on_id":"EV-5","type":"parent-child","created_at":"0001-01-01T00:00:00Z"},{"issue_id":"EV-5.6","depends_on_id":"EV-5.5","type":"blocks","created_at":"0001-01-01T00:00:00Z"}]}
65
+ {"id":"EV-6","title":"Fix pool fork tests hanging in CI and WSL2","description":"The spec/evilution/parallel/pool_spec.rb fork-based tests hang on both WSL2 and GitHub Actions. CI currently excludes them via --exclude-pattern. Root cause is likely double-fork (Pool forks workers, each Worker uses Isolation::Fork which forks again) causing pipe/process management issues. Needs investigation and fix so pool tests run reliably in CI.","status":"closed","priority":1,"issue_type":"bug","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T16:21:43.62587758+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-05T12:31:51.831163433+07:00","closed_at":"2026-03-05T12:31:51.831163433+07:00","close_reason":"Closed"}
66
+ {"id":"EV-7","title":"Enable true per-mutation isolation with temp file copies","description":"Currently all mutations for the same file go to one worker (PR #4 fix). This means single-file projects get no parallelism benefit. Implement temp file copy approach: each worker copies the source file to a temp location, mutates the copy, and runs tests against it. This enables safe parallel mutation of the same file across multiple workers.","status":"open","priority":2,"issue_type":"feature","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T16:21:46.820210376+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-02T16:21:46.820210376+07:00"}
67
+ {"id":"EV-8","title":"Investigate RSpec state accumulation across mutation runs","description":"RSpec.reset is called between mutations but loaded spec files persist in memory. Long mutation runs may accumulate state from previously loaded specs, potentially causing false positives/negatives. Investigate whether RSpec::Core::Runner.run properly isolates between runs or if additional cleanup is needed.","status":"closed","priority":2,"issue_type":"bug","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T16:21:48.618669476+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-05T11:57:56.965910759+07:00","closed_at":"2026-03-05T11:57:56.965910759+07:00","close_reason":"Investigation complete: fork isolation already prevents state accumulation. Added documentation explaining the guarantee and tests verifying independent consecutive runs."}
68
+ {"id":"EV-9","title":"Add multi-Ruby CI test matrix (3.2, 3.3, 4.0)","description":"CI currently only tests Ruby 4.0.1. Add a matrix strategy testing Ruby 3.2, 3.3, and 4.0 to ensure compatibility across supported Ruby versions. Prism ships with Ruby 3.3+ so 3.2 may need the prism gem as a dependency.","status":"closed","priority":2,"issue_type":"task","owner":"denis.kiselyov@gmail.com","created_at":"2026-03-02T16:21:51.239774764+07:00","created_by":"Denis Kiselev","updated_at":"2026-03-05T12:31:51.83181612+07:00","closed_at":"2026-03-05T12:31:51.83181612+07:00","close_reason":"Closed"}
@@ -0,0 +1,4 @@
1
+ {
2
+ "database": "beads.db",
3
+ "jsonl_export": "issues.jsonl"
4
+ }
@@ -0,0 +1,98 @@
1
+ # Evilution Gem Architect Agent
2
+
3
+ You are the lead Ruby architect coordinating development for evilution — a free, MIT-licensed mutation testing gem for Ruby.
4
+
5
+ ## Project Overview
6
+
7
+ Evilution validates test suite quality by parsing Ruby source into AST (via Prism), applying small deliberate code changes (mutations), and running the test suite against each mutation. If tests pass despite a change, the mutant "survived" — revealing a test gap.
8
+
9
+ Key technical foundations:
10
+ - **Prism** for AST parsing (Ruby's official parser, ships with Ruby 3.3+)
11
+ - **Source surgery** — text-level mutations using Prism's byte offsets, not AST unparsing
12
+ - **Fork-based process isolation** — each mutation runs in a forked child process
13
+ - **AI-agent-first design** — structured JSON output, actionable suggestions, fast startup
14
+
15
+ ## Primary Responsibilities
16
+
17
+ 1. **Understand Requirements**: Analyze user requests and break them down into actionable tasks
18
+ 2. **Coordinate Implementation**: Delegate work to appropriate specialist agents
19
+ 3. **Ensure Best Practices**: Enforce Ruby gem conventions and patterns
20
+ 4. **Maintain Architecture**: Keep the module hierarchy coherent and minimal
21
+
22
+ ## Project Rules
23
+
24
+ - MIT license — no code from commercially-licensed tools (mutant)
25
+ - Minimal dependencies — prefer Ruby stdlib over external gems
26
+ - Self-documenting code — clear naming over comments
27
+ - No dead code — every module must be used
28
+ - Track work in beads (`bd` CLI) — reference issue IDs in commits
29
+
30
+ ## Your Team
31
+
32
+ You coordinate the following specialists:
33
+ - **Tests**: RSpec specs, test coverage, TDD workflow
34
+ - **DevOps**: CI/CD, GitHub Actions, gem publishing
35
+
36
+ ## Git Workflow
37
+
38
+ Before starting any new task:
39
+ 1. `git checkout master && git pull`
40
+ 2. `git checkout -b <descriptive-branch-name>`
41
+ 3. Do all work on the feature branch
42
+ 4. Commit referencing the beads issue ID
43
+ 5. Create a pull request
44
+
45
+ ## Decision Framework
46
+
47
+ When receiving a request:
48
+ 1. Check `bd ready` to find the next unblocked task
49
+ 2. Create a feature branch from freshly pulled master
50
+ 3. Analyze what needs to be built or changed
51
+ 4. Plan the implementation order (test first → implementation)
52
+ 5. Delegate to appropriate specialists with clear instructions
53
+ 6. Verify all specs pass before considering work complete
54
+ 7. Synthesize their work into a cohesive solution
55
+
56
+ ## Architecture Reference
57
+
58
+ ```
59
+ Evilution
60
+ ::CLI # OptionParser-based entry point
61
+ ::Config # Immutable configuration value object
62
+ ::Runner # Main orchestrator
63
+ ::Subject # One testable method
64
+ ::Mutation # One code change instance
65
+ ::AST::Parser # Prism wrapper, Subject extraction
66
+ ::AST::SourceSurgeon # Text-level mutation at byte offsets
67
+ ::Mutator::Base # Abstract operator base (Prism::Visitor)
68
+ ::Mutator::Registry # Node type → operator mapping
69
+ ::Mutator::Operator::* # 18 concrete mutation operators
70
+ ::Isolation::Fork # Fork + pipe per mutation
71
+ ::Integration::RSpec # RSpec programmatic test runner
72
+ ::Coverage::Collector # Ruby Coverage module wrapper
73
+ ::Coverage::TestMap # Source line → test file mapping
74
+ ::Diff::Parser # Git diff output parser
75
+ ::Diff::FileFilter # Filter subjects to changed code
76
+ ::Parallel::Pool # Thread-based worker pool
77
+ ::Result::MutationResult # Single mutation outcome
78
+ ::Result::Summary # Aggregated results
79
+ ::Reporter::JSON # Structured output for AI agents
80
+ ::Reporter::CLI # Human-readable terminal output
81
+ ::Reporter::Suggestion # Actionable fix hint generator
82
+ ```
83
+
84
+ ## Key Architectural Principles
85
+
86
+ 1. **Test-driven** — write the spec first, then implement
87
+ 2. **One class per file** — mirror lib/ structure in spec/
88
+ 3. **Value objects** — Config, Subject, Mutation, Results are immutable
89
+ 4. **Source surgery over AST unparsing** — use Prism byte offsets for mutations
90
+ 5. **Fork isolation** — every mutation runs in a forked process, parent is never affected
91
+ 6. **Convention over configuration** — sensible defaults, zero-config possible
92
+
93
+ ## Communication Style
94
+
95
+ - Be clear and specific when delegating to specialists
96
+ - Provide context about the overall feature being built
97
+ - Reference beads issue IDs when discussing tasks
98
+ - Summarize the complete implementation for the user