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.
- checksums.yaml +7 -0
- data/.beads/.gitignore +51 -0
- data/.beads/.migration-hint-ts +1 -0
- data/.beads/README.md +81 -0
- data/.beads/config.yaml +67 -0
- data/.beads/interactions.jsonl +0 -0
- data/.beads/issues.jsonl +68 -0
- data/.beads/metadata.json +4 -0
- data/.claude/prompts/architect.md +98 -0
- data/.claude/prompts/devops.md +106 -0
- data/.claude/prompts/tests.md +160 -0
- data/CHANGELOG.md +19 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +190 -0
- data/Rakefile +12 -0
- data/claude-swarm.yml +28 -0
- data/exe/evilution +6 -0
- data/lib/evilution/ast/parser.rb +83 -0
- data/lib/evilution/ast/source_surgeon.rb +13 -0
- data/lib/evilution/cli.rb +78 -0
- data/lib/evilution/config.rb +98 -0
- data/lib/evilution/coverage/collector.rb +47 -0
- data/lib/evilution/coverage/test_map.rb +25 -0
- data/lib/evilution/diff/file_filter.rb +29 -0
- data/lib/evilution/diff/parser.rb +47 -0
- data/lib/evilution/integration/base.rb +11 -0
- data/lib/evilution/integration/rspec.rb +184 -0
- data/lib/evilution/isolation/fork.rb +70 -0
- data/lib/evilution/mutation.rb +45 -0
- data/lib/evilution/mutator/base.rb +54 -0
- data/lib/evilution/mutator/operator/arithmetic_replacement.rb +37 -0
- data/lib/evilution/mutator/operator/array_literal.rb +22 -0
- data/lib/evilution/mutator/operator/boolean_literal_replacement.rb +31 -0
- data/lib/evilution/mutator/operator/boolean_operator_replacement.rb +50 -0
- data/lib/evilution/mutator/operator/collection_replacement.rb +37 -0
- data/lib/evilution/mutator/operator/comparison_replacement.rb +37 -0
- data/lib/evilution/mutator/operator/conditional_branch.rb +36 -0
- data/lib/evilution/mutator/operator/conditional_negation.rb +36 -0
- data/lib/evilution/mutator/operator/float_literal.rb +26 -0
- data/lib/evilution/mutator/operator/hash_literal.rb +22 -0
- data/lib/evilution/mutator/operator/integer_literal.rb +45 -0
- data/lib/evilution/mutator/operator/method_body_replacement.rb +22 -0
- data/lib/evilution/mutator/operator/negation_insertion.rb +22 -0
- data/lib/evilution/mutator/operator/nil_replacement.rb +20 -0
- data/lib/evilution/mutator/operator/return_value_removal.rb +22 -0
- data/lib/evilution/mutator/operator/statement_deletion.rb +24 -0
- data/lib/evilution/mutator/operator/string_literal.rb +22 -0
- data/lib/evilution/mutator/operator/symbol_literal.rb +20 -0
- data/lib/evilution/mutator/registry.rb +55 -0
- data/lib/evilution/parallel/pool.rb +98 -0
- data/lib/evilution/parallel/worker.rb +24 -0
- data/lib/evilution/reporter/cli.rb +72 -0
- data/lib/evilution/reporter/json.rb +59 -0
- data/lib/evilution/reporter/suggestion.rb +51 -0
- data/lib/evilution/result/mutation_result.rb +37 -0
- data/lib/evilution/result/summary.rb +54 -0
- data/lib/evilution/runner.rb +139 -0
- data/lib/evilution/subject.rb +20 -0
- data/lib/evilution/version.rb +5 -0
- data/lib/evilution.rb +51 -0
- data/sig/evilution.rbs +4 -0
- 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* ⚡
|
data/.beads/config.yaml
ADDED
|
@@ -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
|
data/.beads/issues.jsonl
ADDED
|
@@ -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,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
|