yaic 0.1.0 → 0.2.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/agents/ralph-qa.md +101 -0
  3. data/.claude/ralph/bin/dump-pid.sh +3 -0
  4. data/.claude/ralph/bin/kill-claude +6 -0
  5. data/.claude/ralph/bin/start-ralph +44 -0
  6. data/.claude/ralph/bin/stop-hook.sh +9 -0
  7. data/.claude/ralph/bin/stop-ralph +17 -0
  8. data/.claude/ralph/prompt.md +218 -0
  9. data/.claude/settings.json +26 -0
  10. data/.gitmodules +3 -0
  11. data/CLAUDE.md +65 -0
  12. data/README.md +106 -17
  13. data/Rakefile +8 -0
  14. data/devenv.nix +1 -0
  15. data/docs/agents/data-model.md +150 -0
  16. data/docs/agents/ralph/features/01-message-parsing.md.done +160 -0
  17. data/docs/agents/ralph/features/01-tcpsocket-refactor.md.done +109 -0
  18. data/docs/agents/ralph/features/02-connection-socket.md.done +138 -0
  19. data/docs/agents/ralph/features/02-simplified-client-api.md.done +306 -0
  20. data/docs/agents/ralph/features/03-registration.md.done +147 -0
  21. data/docs/agents/ralph/features/04-ping-pong.md.done +109 -0
  22. data/docs/agents/ralph/features/05-event-system.md.done +167 -0
  23. data/docs/agents/ralph/features/06-privmsg-notice.md.done +163 -0
  24. data/docs/agents/ralph/features/07-join-part.md.done +190 -0
  25. data/docs/agents/ralph/features/08-quit.md.done +118 -0
  26. data/docs/agents/ralph/features/09-nick-change.md.done +109 -0
  27. data/docs/agents/ralph/features/10-topic.md.done +145 -0
  28. data/docs/agents/ralph/features/11-kick.md.done +122 -0
  29. data/docs/agents/ralph/features/12-names.md.done +124 -0
  30. data/docs/agents/ralph/features/13-mode.md.done +174 -0
  31. data/docs/agents/ralph/features/14-who-whois.md.done +188 -0
  32. data/docs/agents/ralph/features/15-client-api.md.done +180 -0
  33. data/docs/agents/ralph/features/16-ssl-test-infrastructure.md.done +50 -0
  34. data/docs/agents/ralph/features/17-github-actions-ci.md.done +70 -0
  35. data/docs/agents/ralph/features/18-brakeman-security-scanning.md.done +67 -0
  36. data/docs/agents/ralph/features/19-fix-qa.md.done +73 -0
  37. data/docs/agents/ralph/features/20-test-optimization.md.done +70 -0
  38. data/docs/agents/ralph/features/21-test-parallelization.md.done +56 -0
  39. data/docs/agents/ralph/features/22-wait-until-pattern.md.done +90 -0
  40. data/docs/agents/ralph/features/23-ping-test-optimization.md.done +46 -0
  41. data/docs/agents/ralph/features/24-blocking-who-whois.md.done +159 -0
  42. data/docs/agents/ralph/features/25-verbose-mode.md.done +166 -0
  43. data/docs/agents/ralph/plans/test-optimization-plan.md +172 -0
  44. data/docs/agents/ralph/progress.md +731 -0
  45. data/docs/agents/todo.md +5 -0
  46. data/lib/yaic/channel.rb +22 -0
  47. data/lib/yaic/client.rb +821 -0
  48. data/lib/yaic/event.rb +35 -0
  49. data/lib/yaic/message.rb +119 -0
  50. data/lib/yaic/registration.rb +17 -0
  51. data/lib/yaic/socket.rb +120 -0
  52. data/lib/yaic/source.rb +39 -0
  53. data/lib/yaic/version.rb +1 -1
  54. data/lib/yaic/who_result.rb +17 -0
  55. data/lib/yaic/whois_result.rb +20 -0
  56. data/lib/yaic.rb +13 -1
  57. metadata +51 -1
@@ -0,0 +1,188 @@
1
+ # WHO and WHOIS
2
+
3
+ ## Description
4
+
5
+ Implement user information queries. WHO lists users matching criteria, WHOIS provides detailed info about a specific user.
6
+
7
+ ## Behavior
8
+
9
+ ### WHO Command
10
+
11
+ ```ruby
12
+ client.who("#ruby") # List users in channel
13
+ client.who("nick") # Get info on specific user
14
+ ```
15
+
16
+ Format: `WHO <mask>`
17
+
18
+ ### WHO Response
19
+
20
+ - 352 RPL_WHOREPLY - One per matching user
21
+ - 315 RPL_ENDOFWHO - End of list
22
+
23
+ RPL_WHOREPLY format:
24
+ `:server 352 mynick #chan ~user host server nick H :0 realname`
25
+
26
+ Fields:
27
+ - channel or `*`
28
+ - username
29
+ - host
30
+ - server
31
+ - nick
32
+ - flags: H (here) or G (gone/away), optionally `*` (ircop)
33
+ - hopcount and realname (after colon)
34
+
35
+ ### WHOIS Command
36
+
37
+ ```ruby
38
+ client.whois("dan")
39
+ ```
40
+
41
+ Format: `WHOIS <nick>`
42
+
43
+ ### WHOIS Response
44
+
45
+ Common numerics:
46
+ - 311 RPL_WHOISUSER - `nick user host * :realname`
47
+ - 319 RPL_WHOISCHANNELS - Channel list
48
+ - 312 RPL_WHOISSERVER - Server info
49
+ - 317 RPL_WHOISIDLE - Idle time
50
+ - 330 RPL_WHOISACCOUNT - Account name (if identified)
51
+ - 318 RPL_ENDOFWHOIS - End of WHOIS
52
+
53
+ ### WHOIS Errors
54
+
55
+ - 401 ERR_NOSUCHNICK - Nick not found
56
+ - 318 RPL_ENDOFWHOIS - Still sent on error
57
+
58
+ ### Events
59
+
60
+ For WHO, can emit individual results or collected batch.
61
+
62
+ For WHOIS, collect all numerics until ENDOFWHOIS, then emit `:whois` event with aggregated data.
63
+
64
+ ## Models
65
+
66
+ ```ruby
67
+ Yaic::WhoisResult
68
+ - nick: String
69
+ - user: String
70
+ - host: String
71
+ - realname: String
72
+ - channels: Array[String]
73
+ - server: String
74
+ - idle: Integer (seconds)
75
+ - signon: Time
76
+ - account: String or nil
77
+ - away: String or nil
78
+ ```
79
+
80
+ ## Tests
81
+
82
+ ### Integration Tests - WHO
83
+
84
+ **WHO channel**
85
+ - Given: Client in #test with users
86
+ - When: `client.who("#test")`
87
+ - Then: Receive RPL_WHOREPLY for each user, then RPL_ENDOFWHO
88
+
89
+ **WHO specific nick**
90
+ - Given: "target" is online
91
+ - When: `client.who("target")`
92
+ - Then: Receive single RPL_WHOREPLY
93
+
94
+ **WHO non-existent**
95
+ - Given: No such channel/user
96
+ - When: `client.who("nobody")`
97
+ - Then: Receive only RPL_ENDOFWHO (empty results)
98
+
99
+ ### Integration Tests - WHOIS
100
+
101
+ **WHOIS user**
102
+ - Given: "target" is online
103
+ - When: `client.whois("target")`
104
+ - Then: Receive RPL_WHOISUSER, RPL_WHOISSERVER, RPL_ENDOFWHOIS
105
+
106
+ **WHOIS with channels**
107
+ - Given: "target" is in channels
108
+ - When: `client.whois("target")`
109
+ - Then: RPL_WHOISCHANNELS shows their channels
110
+
111
+ **WHOIS non-existent**
112
+ - Given: No such nick
113
+ - When: `client.whois("nobody")`
114
+ - Then: Receive 401 ERR_NOSUCHNICK, then RPL_ENDOFWHOIS
115
+
116
+ **WHOIS away user**
117
+ - Given: "target" is away
118
+ - When: `client.whois("target")`
119
+ - Then: Receive 301 RPL_AWAY with away message
120
+
121
+ ### Unit Tests - WHO
122
+
123
+ **Parse RPL_WHOREPLY**
124
+ - Given: `:server 352 me #chan ~user host srv nick H :0 Real Name`
125
+ - When: Parse
126
+ - Then: channel="#chan", user="~user", nick="nick", realname="Real Name", away=false
127
+
128
+ **Parse RPL_WHOREPLY away**
129
+ - Given: `:server 352 me #chan ~user host srv nick G :0 Name`
130
+ - When: Parse
131
+ - Then: away=true (G flag)
132
+
133
+ **Format WHO**
134
+ - Given: mask = "#test"
135
+ - When: Build WHO
136
+ - Then: Output = "WHO #test\r\n"
137
+
138
+ ### Unit Tests - WHOIS
139
+
140
+ **Parse RPL_WHOISUSER**
141
+ - Given: `:server 311 me nick ~user host * :Real Name`
142
+ - When: Parse
143
+ - Then: nick="nick", user="~user", host="host", realname="Real Name"
144
+
145
+ **Parse RPL_WHOISCHANNELS**
146
+ - Given: `:server 319 me nick :#chan1 @#chan2 +#chan3`
147
+ - When: Parse
148
+ - Then: channels=["#chan1", "#chan2", "#chan3"] with modes noted
149
+
150
+ **Parse RPL_WHOISIDLE**
151
+ - Given: `:server 317 me nick 300 1234567890 :seconds idle`
152
+ - When: Parse
153
+ - Then: idle=300, signon=Time.at(1234567890)
154
+
155
+ **Parse RPL_WHOISACCOUNT**
156
+ - Given: `:server 330 me nick account :is logged in as`
157
+ - When: Parse
158
+ - Then: account="account"
159
+
160
+ **Format WHOIS**
161
+ - Given: nick = "target"
162
+ - When: Build WHOIS
163
+ - Then: Output = "WHOIS target\r\n"
164
+
165
+ ### Collection Tests
166
+
167
+ **Collect WHOIS parts**
168
+ - Given: WHOIS in progress
169
+ - When: RPL_WHOISUSER, RPL_WHOISCHANNELS, RPL_WHOISSERVER, RPL_ENDOFWHOIS received
170
+ - Then: Single :whois event with all data
171
+
172
+ **Handle interleaved messages**
173
+ - Given: WHOIS in progress
174
+ - When: Other messages arrive between WHOIS numerics
175
+ - Then: WHOIS data still collected correctly
176
+
177
+ ## Implementation Notes
178
+
179
+ - WHOIS numerics may be interleaved with other messages
180
+ - Buffer WHOIS results until ENDOFWHOIS
181
+ - Implement timeout for WHOIS (server may not respond)
182
+ - RPL_WHOISCHANNELS may have mode prefixes (@, +)
183
+ - WHO visibility affected by +i mode
184
+
185
+ ## Dependencies
186
+
187
+ - Requires `01-message-parsing.md`
188
+ - Requires `05-event-system.md`
@@ -0,0 +1,180 @@
1
+ # Client API
2
+
3
+ ## Description
4
+
5
+ Implement the main `Yaic::Client` class that ties everything together and provides the public interface.
6
+
7
+ ## Behavior
8
+
9
+ ### Initialization
10
+
11
+ ```ruby
12
+ client = Yaic::Client.new(
13
+ server: "irc.libera.chat",
14
+ port: 6697,
15
+ ssl: true,
16
+ nickname: "mynick",
17
+ username: "myuser", # optional, defaults to nickname
18
+ realname: "My Real Name" # optional, defaults to nickname
19
+ )
20
+ ```
21
+
22
+ ### Connection
23
+
24
+ ```ruby
25
+ client.connect # Blocking - connects and starts event loop
26
+ ```
27
+
28
+ ### Event Registration
29
+
30
+ ```ruby
31
+ client.on(:message) { |event| puts event.text }
32
+ client.on(:join) { |event| puts "#{event.user} joined #{event.channel}" }
33
+ ```
34
+
35
+ ### Commands
36
+
37
+ ```ruby
38
+ client.join("#ruby")
39
+ client.join("#ruby", "key")
40
+ client.part("#ruby")
41
+ client.part("#ruby", "reason")
42
+ client.privmsg("#ruby", "Hello!")
43
+ client.privmsg("nick", "Private message")
44
+ client.notice("#ruby", "Notice")
45
+ client.nick("newnick")
46
+ client.topic("#ruby")
47
+ client.topic("#ruby", "New topic")
48
+ client.quit
49
+ client.quit("Goodbye")
50
+ client.kick("#ruby", "nick")
51
+ client.kick("#ruby", "nick", "reason")
52
+ client.mode("#ruby")
53
+ client.mode("#ruby", "+m")
54
+ client.who("#ruby")
55
+ client.whois("nick")
56
+ client.names("#ruby")
57
+ ```
58
+
59
+ ### State Access
60
+
61
+ ```ruby
62
+ client.nick # Current nickname
63
+ client.connected? # Boolean
64
+ client.channels # Hash of joined channels
65
+ client.server # Server hostname
66
+ ```
67
+
68
+ ### Error Handling
69
+
70
+ - Connection errors raise appropriate exceptions
71
+ - Server errors emit `:error` events
72
+
73
+ ## Models
74
+
75
+ ```ruby
76
+ Yaic::Client
77
+ - config: Hash
78
+ - socket: Yaic::Socket
79
+ - handlers: Hash[Symbol, Array[Block]]
80
+ - channels: Hash[String, Yaic::Channel]
81
+ - nick: String
82
+ - state: Symbol
83
+ ```
84
+
85
+ ## Tests
86
+
87
+ ### Integration Tests - Full Flow
88
+
89
+ **Connect and receive welcome**
90
+ - Given: New client configured for inspircd
91
+ - When: `client.connect`
92
+ - Then: Connected, :connect event fired
93
+
94
+ **Join channel and send message**
95
+ - Given: Connected client
96
+ - When: Join #test, send PRIVMSG
97
+ - Then: Message received by other client in channel
98
+
99
+ **Receive and handle message**
100
+ - Given: Connected client in #test with :message handler
101
+ - When: Other client sends message
102
+ - Then: Handler called with correct event
103
+
104
+ **Full session lifecycle**
105
+ - Given: New client
106
+ - When: Connect, join, chat, part, quit
107
+ - Then: All operations succeed, clean disconnect
108
+
109
+ ### Unit Tests - Initialization
110
+
111
+ **Default values**
112
+ - Given: Only server, port, ssl, nickname provided
113
+ - When: Create client
114
+ - Then: username = nickname, realname = nickname
115
+
116
+ **Store configuration**
117
+ - Given: Full config provided
118
+ - When: Create client
119
+ - Then: All values accessible
120
+
121
+ ### Unit Tests - State
122
+
123
+ **Initially disconnected**
124
+ - Given: New client
125
+ - Then: `client.connected?` = false, `client.state` = :disconnected
126
+
127
+ **After connect**
128
+ - Given: Client connects successfully
129
+ - Then: `client.connected?` = true, `client.state` = :connected
130
+
131
+ **After quit**
132
+ - Given: Connected client quits
133
+ - Then: `client.connected?` = false
134
+
135
+ **Track nickname**
136
+ - Given: Connected as "oldnick"
137
+ - When: Nick changed to "newnick"
138
+ - Then: `client.nick` = "newnick"
139
+
140
+ **Track channels**
141
+ - Given: Connected client
142
+ - When: Join #test
143
+ - Then: `client.channels["#test"]` exists
144
+
145
+ ### Unit Tests - Command Methods
146
+
147
+ **join delegates to socket**
148
+ - Given: Connected client
149
+ - When: `client.join("#test")`
150
+ - Then: "JOIN #test" sent
151
+
152
+ **privmsg delegates to socket**
153
+ - Given: Connected client
154
+ - When: `client.privmsg("#test", "Hello")`
155
+ - Then: "PRIVMSG #test :Hello" sent
156
+
157
+ ### Error Handling Tests
158
+
159
+ **Connection refused**
160
+ - Given: No server on port
161
+ - When: `client.connect`
162
+ - Then: Raises connection error
163
+
164
+ **Server error numeric**
165
+ - Given: Connected client with :error handler
166
+ - When: Server sends 433 (nick in use)
167
+ - Then: Handler called with error info
168
+
169
+ ## Implementation Notes
170
+
171
+ - `connect` should handle the full registration sequence
172
+ - Consider thread-safety for handlers
173
+ - Event loop reads from socket, parses messages, dispatches events
174
+ - All command methods should validate state (connected?) before sending
175
+ - Consider `connect_async` for non-blocking usage
176
+
177
+ ## Dependencies
178
+
179
+ - Requires all previous features
180
+ - This is the final integration feature
@@ -0,0 +1,50 @@
1
+ # SSL Test Infrastructure
2
+
3
+ ## Description
4
+
5
+ Set up proper SSL/TLS testing infrastructure so that SSL-related tests can run reliably. This includes configuring the inspircd Docker container with SSL certificates and ensuring tests can connect over TLS.
6
+
7
+ ## Behavior
8
+
9
+ ### Container Configuration
10
+
11
+ 1. Create or configure inspircd container with SSL enabled on port 6697
12
+ 2. Generate self-signed certificates for testing
13
+ 3. Mount certificates into the container
14
+ 4. Update `bin/start-irc-server` to set up SSL-enabled container
15
+
16
+ ### Test Updates
17
+
18
+ 1. Remove skip logic from SSL tests in `test/integration/socket_test.rb`
19
+ 2. SSL tests should run and pass reliably
20
+ 3. Verify both SSL connection and read/write operations work
21
+
22
+ ## Tests
23
+
24
+ **SSL connection succeeds**
25
+ - Given: inspircd with SSL on localhost:6697
26
+ - When: Connect with ssl: true, verify_mode: VERIFY_NONE
27
+ - Then: Connection established, state is :connecting
28
+
29
+ **SSL read/write works**
30
+ - Given: SSL connection established
31
+ - When: Send NICK/USER commands
32
+ - Then: Receive server responses
33
+
34
+ **SSL certificate verification**
35
+ - Given: Self-signed cert on server
36
+ - When: Connect with VERIFY_PEER
37
+ - Then: Fails unless cert is trusted
38
+ - When: Connect with VERIFY_NONE
39
+ - Then: Succeeds
40
+
41
+ ## Implementation Notes
42
+
43
+ - Use OpenSSL to generate self-signed certs: `openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes`
44
+ - Store certs in `test/fixtures/ssl/` or similar
45
+ - May need custom inspircd.conf to enable SSL module
46
+ - Update `bin/stop-irc-server` if container setup changes
47
+
48
+ ## Dependencies
49
+
50
+ - Requires `02-connection-socket.md` to be complete (SSL support in Socket class)
@@ -0,0 +1,70 @@
1
+ # GitHub Actions CI
2
+
3
+ ## Description
4
+
5
+ Set up GitHub Actions to run tests and linting on pull requests and pushes to the main branch. Tests run on Ruby 3.2 and 3.4 (bottom and top of current EOL lifecycle). Linting runs as a separate job.
6
+
7
+ ## Behavior
8
+
9
+ ### Workflow Triggers
10
+
11
+ The workflow runs on:
12
+ - Push to `main` branch
13
+ - All pull requests
14
+
15
+ ### Jobs
16
+
17
+ **1. Lint Job**
18
+ - Runs `bundle exec standardrb` (or `bundle exec rake standard`)
19
+ - Single job, not matrixed
20
+ - Fails fast if code doesn't pass linting
21
+
22
+ **2. Test Job**
23
+ - Matrix: Ruby 3.2 and Ruby 3.4
24
+ - Runs `bundle exec rake test`
25
+ - Uses `ruby/setup-ruby@v1` with `bundler-cache: true`
26
+
27
+ ### Workflow File
28
+
29
+ Located at `.github/workflows/main.yml` (update existing file).
30
+
31
+ ## Implementation Notes
32
+
33
+ - The existing workflow triggers on `master` which doesn't exist - change to `main`
34
+ - Current workflow only tests Ruby 3.4.1 - expand to matrix with 3.2 and 3.4
35
+ - Split lint into its own job so it fails fast and doesn't duplicate across matrix
36
+ - Use `actions/checkout@v4` with `persist-credentials: false`
37
+
38
+ ## Tests
39
+
40
+ This feature has no unit tests. Verification is done by:
41
+
42
+ 1. Push the workflow changes to a branch
43
+ 2. Open a PR or push to main
44
+ 3. Verify CI runs successfully using `gh run list` and `gh run view`
45
+ 4. All jobs (lint, test on 3.2, test on 3.4) must pass
46
+
47
+ ### Verification Commands
48
+
49
+ ```bash
50
+ # Check recent workflow runs
51
+ gh run list --limit 5
52
+
53
+ # View specific run details
54
+ gh run view <run-id>
55
+
56
+ # Check if latest run on current branch passed
57
+ gh run list --branch $(git branch --show-current) --limit 1
58
+ ```
59
+
60
+ ## Completion Criteria
61
+
62
+ - [ ] `.github/workflows/main.yml` updated with correct configuration
63
+ - [ ] Workflow triggers on `main` branch (not `master`)
64
+ - [ ] Lint job runs separately
65
+ - [ ] Test matrix includes Ruby 3.2 and 3.4
66
+ - [ ] CI run passes (verified via `gh run list` showing success)
67
+
68
+ ## Dependencies
69
+
70
+ None - this is the first feature.
@@ -0,0 +1,67 @@
1
+ # Brakeman Security Scanning
2
+
3
+ ## Description
4
+
5
+ Add Brakeman security scanning to CI. Brakeman is a static analysis tool that checks Ruby on Rails applications for security vulnerabilities. This runs as a separate GitHub Actions job.
6
+
7
+ ## Behavior
8
+
9
+ ### Workflow Integration
10
+
11
+ Add a new job to `.github/workflows/main.yml`:
12
+
13
+ **Security Job**
14
+ - Runs `bin/brakeman` (or `bundle exec brakeman`)
15
+ - Single job, not matrixed (security scanning doesn't need multiple Ruby versions)
16
+ - Can run in parallel with other jobs
17
+
18
+ ### Brakeman Setup
19
+
20
+ If `bin/brakeman` doesn't exist, create it as a binstub or run via `bundle exec brakeman`.
21
+
22
+ Add `brakeman` gem to Gemfile if not present (in development/test group).
23
+
24
+ ## Implementation Notes
25
+
26
+ - Brakeman may report existing issues in the codebase
27
+ - If Brakeman fails, fix the issues or configure Brakeman to ignore false positives
28
+ - Use `brakeman --no-pager` for CI output
29
+ - Consider `brakeman -o /dev/stdout -o brakeman-output.html` for both console and artifact output
30
+
31
+ ### Handling Existing Issues
32
+
33
+ If the codebase has existing Brakeman warnings:
34
+ 1. Run `brakeman` locally first
35
+ 2. Fix any real security issues
36
+ 3. For false positives, use `brakeman -I` to create/update `config/brakeman.ignore`
37
+ 4. Commit the ignore file if needed
38
+
39
+ ## Tests
40
+
41
+ This feature has no unit tests. Verification is done by:
42
+
43
+ 1. Ensure Brakeman passes locally: `bundle exec brakeman`
44
+ 2. Push changes and verify CI runs
45
+ 3. Security job must pass in GitHub Actions
46
+
47
+ ### Verification Commands
48
+
49
+ ```bash
50
+ # Run Brakeman locally
51
+ bundle exec brakeman
52
+
53
+ # Check CI status
54
+ gh run list --limit 5
55
+ gh run view <run-id>
56
+ ```
57
+
58
+ ## Completion Criteria
59
+
60
+ - [ ] Brakeman gem added to Gemfile (if not present)
61
+ - [ ] Brakeman runs successfully locally with no errors
62
+ - [ ] Security job added to `.github/workflows/main.yml`
63
+ - [ ] CI run passes including the security job (verified via `gh run list`)
64
+
65
+ ## Dependencies
66
+
67
+ - Requires `17-github-actions-ci.md` (workflow file must exist and work)
@@ -0,0 +1,73 @@
1
+ Look at 02-simplified-client-api.md.done
2
+ An agent flag that feature as done without the QA passing on it. Which is TOTALLY UNACCEPTABLE.
3
+
4
+ Do not rerun QA before you're ready to commit. I'll give you the QA output:
5
+
6
+ ```
7
+ QA FAILED. Issues found:
8
+
9
+ 1. Public timeout parameters violate feature spec (/Users/joedupuis/workspace/yaic/lib/yaic/client.rb lines
10
+ 55, 159, 166, 184):
11
+ - The feature spec at
12
+ /Users/joedupuis/workspace/yaic/docs/agents/ralph/features/02-simplified-client-api.md.done explicitly
13
+ states:
14
+ - Line 32: "All methods block until the operation completes. No bangs, no timeout params, no manual
15
+ socket handling."
16
+ - Lines 86-90: "Timeouts are an internal concern. Use sensible defaults... Users don't need to think
17
+ about this."
18
+ - However, the implementation exposes timeout: keyword arguments in the public API:
19
+ def connect(timeout: DEFAULT_CONNECT_TIMEOUT)
20
+ def join(channel, key = nil, timeout: DEFAULT_OPERATION_TIMEOUT)
21
+ def part(channel, reason = nil, timeout: DEFAULT_OPERATION_TIMEOUT)
22
+ def nick(new_nick = nil, timeout: DEFAULT_OPERATION_TIMEOUT)
23
+ - Fix: Remove the public timeout: parameter from these method signatures. Keep the internal constants and
24
+ use them directly in wait_until.
25
+ 2. Integration tests still use instance_variable_get(:@socket) (Multiple files):
26
+ - /Users/joedupuis/workspace/yaic/test/integration/mode_test.rb lines 79, 103, 130
27
+ - /Users/joedupuis/workspace/yaic/test/integration/kick_test.rb lines 17, 43, 88, 110, 146
28
+ - /Users/joedupuis/workspace/yaic/test/integration/names_test.rb lines 34, 63, 91
29
+ - /Users/joedupuis/workspace/yaic/test/integration/nick_test.rb lines 33, 51
30
+ - /Users/joedupuis/workspace/yaic/test/integration/join_part_test.rb lines 53, 108
31
+ - /Users/joedupuis/workspace/yaic/test/integration/who_whois_test.rb line 133
32
+ - The feature spec (lines 136-139) explicitly says to remove:
33
+ - instance_variable_get
34
+ - Manual read loops
35
+ - Custom wait helpers
36
+ - on_socket_connected
37
+ - These tests use instance_variable_get(:@socket) to call become_oper and send raw commands like OPER and
38
+ SAMODE.
39
+ - Fix: Either add a public raw or send_raw method to the Client class for sending raw IRC commands, or
40
+ refactor the tests to not require OPER privileges (if possible). The become_oper helper pattern using direct
41
+ socket access is exactly what the feature was meant to eliminate.
42
+
43
+ Required fixes:
44
+ 1. Remove timeout: parameter from the public method signatures of connect, join, part, and nick.
45
+ 2. Either add a public raw(command) method to send arbitrary IRC commands, or refactor integration tests
46
+ that need OPER privileges to avoid accessing internal socket.
47
+ ```
48
+
49
+ and
50
+
51
+ ```
52
+ Two issues found:
53
+
54
+ 1. Public timeout parameters violate feature spec - The methods connect, join, part, and nick expose timeout:
55
+ keyword arguments, but the feature spec explicitly states "No bangs, no timeout params" and "Timeouts are an
56
+ internal concern."
57
+ 2. Integration tests still use instance_variable_get(:@socket) - Multiple integration tests access the internal
58
+ socket directly via instance_variable_get(:@socket) to call become_oper and send raw commands. The feature spec
59
+ says to remove this pattern.
60
+
61
+ Required fixes:
62
+ 1. Remove timeout: parameter from public method signatures
63
+ 2. Add a public raw(command) method for sending arbitrary IRC commands, or refactor the tests
64
+ ```
65
+
66
+
67
+ Fix the mess. If you cant stop and ask me questions.
68
+
69
+
70
+ I think the timeout is fine. Let's ignore the first part. The second part though with the reaching for instance variable is bad.
71
+ The tests should not have to reach out for internals with instance_variable_get.
72
+
73
+ If you are blocked ask me with the ask question tool.
@@ -0,0 +1,70 @@
1
+ # Test Optimization - Planning
2
+
3
+ ## Description
4
+
5
+ The test suite is slow (173 seconds) and needs optimization. This feature involves profiling the tests to identify slow ones, analyzing why they are slow, and creating an optimization plan for user approval.
6
+
7
+ ## Behavior
8
+
9
+ ### Phase 1: Profiling
10
+
11
+ Run the full test suite with timing enabled using `rake test TESTOPTS="-v"` and capture:
12
+ - Total time for each test file
13
+ - Individual test method times
14
+ - Identify the slowest tests (top 10 or anything over 1 second)
15
+
16
+ ### Phase 2: Analysis
17
+
18
+ For each slow test, analyze:
19
+ - Is it an integration test hitting a real IRC server?
20
+ - Does it have unnecessary sleeps or timeouts?
21
+ - Is it doing redundant setup?
22
+ - Could it be parallelized?
23
+ - Is it testing too much in one test?
24
+
25
+ Document findings with specific line numbers and explanations.
26
+
27
+ ### Phase 3: Plan Creation
28
+
29
+ Create a plan document at `docs/agents/ralph/plans/test-optimization-plan.md` containing:
30
+ - Summary of profiling results (slowest tests with times)
31
+ - Root causes identified
32
+ - Proposed optimizations with expected impact
33
+ - Risk assessment for each change
34
+ - How test coverage will be preserved
35
+
36
+ ### Phase 4: User Approval
37
+
38
+ Use `AskUserQuestion` tool to ask the user to review and approve the plan.
39
+
40
+ If not approved, update the plan based on feedback and ask again.
41
+
42
+ ## Tests
43
+
44
+ This feature is meta - it's about planning, not adding new functionality. Success criteria:
45
+
46
+ **Profiling Output**
47
+ - Generate a report showing test execution times
48
+ - Identify tests taking > 500ms
49
+
50
+ **Plan Document**
51
+ - Plan exists at docs/agents/ralph/plans/test-optimization-plan.md
52
+ - Contains profiling results with specific times
53
+ - Contains proposed changes with rationale
54
+ - Contains risk assessment
55
+
56
+ ## Implementation Notes
57
+
58
+ - Use `rake test TESTOPTS="-v"` for timing
59
+ - Use `bundle exec standardrb -A` for linting
60
+
61
+ ## Dependencies
62
+
63
+ None - this is the first feature.
64
+
65
+ ## Next Features
66
+
67
+ After this planning feature is complete, the following implementation features should be created:
68
+ - 21-test-parallelization.md - Enable parallel test execution
69
+ - 22-wait-until-pattern.md - Replace sleep/read_multiple with wait_until
70
+ - 23-ping-test-optimization.md - Optimize the ping test with faster server config