source_monitor 0.7.1 → 0.8.1

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/commands/release.md +18 -6
  3. data/.claude/skills/sm-configure/SKILL.md +10 -1
  4. data/.claude/skills/sm-configure/reference/configuration-reference.md +44 -0
  5. data/.claude/skills/sm-host-setup/reference/initializer-template.md +17 -0
  6. data/.claude/skills/sm-host-setup/reference/setup-checklist.md +2 -0
  7. data/.claude/skills/sm-job/reference/job-conventions.md +26 -0
  8. data/.claude/skills/sm-upgrade/reference/version-history.md +22 -0
  9. data/.gitignore +10 -0
  10. data/AGENTS.md +1 -1
  11. data/CHANGELOG.md +45 -0
  12. data/CLAUDE.md +24 -3
  13. data/Gemfile.lock +1 -1
  14. data/README.md +6 -4
  15. data/Rakefile +0 -2
  16. data/VERSION +1 -1
  17. data/app/assets/builds/source_monitor/application.css +43 -0
  18. data/app/assets/builds/source_monitor/application.js +127 -0
  19. data/app/assets/builds/source_monitor/application.js.map +3 -3
  20. data/app/assets/javascripts/source_monitor/application.js +2 -0
  21. data/app/assets/javascripts/source_monitor/controllers/notification_container_controller.js +138 -0
  22. data/app/assets/javascripts/source_monitor/controllers/notification_controller.js +11 -0
  23. data/app/controllers/source_monitor/source_favicon_fetches_controller.rb +38 -0
  24. data/app/controllers/source_monitor/sources_controller.rb +11 -0
  25. data/app/helpers/source_monitor/application_helper.rb +51 -0
  26. data/app/jobs/source_monitor/favicon_fetch_job.rb +71 -0
  27. data/app/jobs/source_monitor/import_opml_job.rb +9 -0
  28. data/app/jobs/source_monitor/source_health_check_job.rb +10 -0
  29. data/app/models/source_monitor/source.rb +2 -0
  30. data/app/views/layouts/source_monitor/application.html.erb +23 -2
  31. data/app/views/source_monitor/import_sessions/steps/_preview.html.erb +7 -2
  32. data/app/views/source_monitor/shared/_toast.html.erb +1 -0
  33. data/app/views/source_monitor/sources/_details.html.erb +34 -5
  34. data/app/views/source_monitor/sources/_row.html.erb +11 -6
  35. data/config/routes.rb +1 -0
  36. data/docs/configuration.md +1 -1
  37. data/docs/upgrade.md +22 -0
  38. data/lib/generators/source_monitor/install/templates/source_monitor.rb.tt +15 -1
  39. data/lib/source_monitor/configuration/favicons_settings.rb +42 -0
  40. data/lib/source_monitor/configuration/http_settings.rb +1 -1
  41. data/lib/source_monitor/configuration/scraping_settings.rb +1 -1
  42. data/lib/source_monitor/configuration.rb +3 -1
  43. data/lib/source_monitor/favicons/discoverer.rb +196 -0
  44. data/lib/source_monitor/fetching/feed_fetcher/source_updater.rb +21 -0
  45. data/lib/source_monitor/fetching/feed_fetcher.rb +1 -0
  46. data/lib/source_monitor/http.rb +5 -3
  47. data/lib/source_monitor/version.rb +1 -1
  48. data/lib/source_monitor.rb +4 -0
  49. data/source_monitor.gemspec +1 -1
  50. metadata +6 -106
  51. data/.vbw-planning/PROJECT.md +0 -51
  52. data/.vbw-planning/ROADMAP.md +0 -53
  53. data/.vbw-planning/SHIPPED.md +0 -63
  54. data/.vbw-planning/STATE.md +0 -27
  55. data/.vbw-planning/codebase/ARCHITECTURE.md +0 -147
  56. data/.vbw-planning/codebase/CONCERNS.md +0 -99
  57. data/.vbw-planning/codebase/CONVENTIONS.md +0 -97
  58. data/.vbw-planning/codebase/DEPENDENCIES.md +0 -100
  59. data/.vbw-planning/codebase/INDEX.md +0 -86
  60. data/.vbw-planning/codebase/META.md +0 -42
  61. data/.vbw-planning/codebase/PATTERNS.md +0 -262
  62. data/.vbw-planning/codebase/STACK.md +0 -101
  63. data/.vbw-planning/codebase/STRUCTURE.md +0 -324
  64. data/.vbw-planning/codebase/TESTING.md +0 -154
  65. data/.vbw-planning/config.json +0 -53
  66. data/.vbw-planning/discovery.json +0 -26
  67. data/.vbw-planning/milestones/default/ROADMAP.md +0 -115
  68. data/.vbw-planning/milestones/default/STATE.md +0 -82
  69. data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-01-SUMMARY.md +0 -56
  70. data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-01.md +0 -187
  71. data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-02-SUMMARY.md +0 -64
  72. data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-02.md +0 -137
  73. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-01-SUMMARY.md +0 -67
  74. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-01.md +0 -142
  75. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-02-SUMMARY.md +0 -64
  76. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-02.md +0 -138
  77. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-03-SUMMARY.md +0 -85
  78. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-03.md +0 -147
  79. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-04-SUMMARY.md +0 -63
  80. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-04.md +0 -129
  81. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-05-SUMMARY.md +0 -74
  82. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-05.md +0 -154
  83. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/03-VERIFICATION-wave1.md +0 -303
  84. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/03-VERIFICATION.md +0 -510
  85. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-01-SUMMARY.md +0 -61
  86. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-01.md +0 -161
  87. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-02-SUMMARY.md +0 -66
  88. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-02.md +0 -132
  89. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-03-SUMMARY.md +0 -59
  90. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-03.md +0 -171
  91. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-04-SUMMARY.md +0 -56
  92. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-04.md +0 -152
  93. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/04-CONTEXT.md +0 -33
  94. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-01-SUMMARY.md +0 -42
  95. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-01.md +0 -119
  96. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-02-SUMMARY.md +0 -52
  97. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-02.md +0 -195
  98. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-03-SUMMARY.md +0 -79
  99. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-03.md +0 -130
  100. data/.vbw-planning/milestones/generator-enhancements/REQUIREMENTS.md +0 -72
  101. data/.vbw-planning/milestones/generator-enhancements/ROADMAP.md +0 -125
  102. data/.vbw-planning/milestones/generator-enhancements/SHIPPED.md +0 -40
  103. data/.vbw-planning/milestones/generator-enhancements/STATE.md +0 -43
  104. data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/01-CONTEXT.md +0 -33
  105. data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/01-VERIFICATION.md +0 -86
  106. data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/PLAN-01-SUMMARY.md +0 -61
  107. data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/PLAN-01.md +0 -380
  108. data/.vbw-planning/milestones/generator-enhancements/phases/02-verification/02-VERIFICATION.md +0 -78
  109. data/.vbw-planning/milestones/generator-enhancements/phases/02-verification/PLAN-01-SUMMARY.md +0 -46
  110. data/.vbw-planning/milestones/generator-enhancements/phases/02-verification/PLAN-01.md +0 -500
  111. data/.vbw-planning/milestones/generator-enhancements/phases/03-docs-alignment/03-VERIFICATION.md +0 -89
  112. data/.vbw-planning/milestones/generator-enhancements/phases/03-docs-alignment/PLAN-01-SUMMARY.md +0 -48
  113. data/.vbw-planning/milestones/generator-enhancements/phases/03-docs-alignment/PLAN-01.md +0 -456
  114. data/.vbw-planning/milestones/generator-enhancements/phases/04-dashboard-ux/04-VERIFICATION.md +0 -129
  115. data/.vbw-planning/milestones/generator-enhancements/phases/04-dashboard-ux/PLAN-01-SUMMARY.md +0 -70
  116. data/.vbw-planning/milestones/generator-enhancements/phases/04-dashboard-ux/PLAN-01.md +0 -747
  117. data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/05-VERIFICATION.md +0 -156
  118. data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-01-SUMMARY.md +0 -69
  119. data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-01.md +0 -455
  120. data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-02-SUMMARY.md +0 -39
  121. data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-02.md +0 -488
  122. data/.vbw-planning/milestones/generator-enhancements/phases/06-netflix-feed-fix/06-VERIFICATION.md +0 -100
  123. data/.vbw-planning/milestones/generator-enhancements/phases/06-netflix-feed-fix/PLAN-01-SUMMARY.md +0 -37
  124. data/.vbw-planning/milestones/generator-enhancements/phases/06-netflix-feed-fix/PLAN-01.md +0 -345
  125. data/.vbw-planning/milestones/upgrade-assurance/REQUIREMENTS.md +0 -80
  126. data/.vbw-planning/milestones/upgrade-assurance/ROADMAP.md +0 -75
  127. data/.vbw-planning/milestones/upgrade-assurance/STATE.md +0 -29
  128. data/.vbw-planning/milestones/upgrade-assurance/phases/01-upgrade-command/01-VERIFICATION.md +0 -144
  129. data/.vbw-planning/milestones/upgrade-assurance/phases/01-upgrade-command/PLAN-01-SUMMARY.md +0 -43
  130. data/.vbw-planning/milestones/upgrade-assurance/phases/01-upgrade-command/PLAN-01.md +0 -405
  131. data/.vbw-planning/milestones/upgrade-assurance/phases/02-config-deprecation/PLAN-01-SUMMARY.md +0 -27
  132. data/.vbw-planning/milestones/upgrade-assurance/phases/02-config-deprecation/PLAN-01.md +0 -303
  133. data/.vbw-planning/milestones/upgrade-assurance/phases/03-upgrade-skill-docs/03-VERIFICATION.md +0 -380
  134. data/.vbw-planning/milestones/upgrade-assurance/phases/03-upgrade-skill-docs/PLAN-01-SUMMARY.md +0 -36
  135. data/.vbw-planning/milestones/upgrade-assurance/phases/03-upgrade-skill-docs/PLAN-01.md +0 -652
  136. data/.vbw-planning/phases/01-aia-certificate-resolution/.context-dev.md +0 -17
  137. data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-01-SUMMARY.md +0 -26
  138. data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-01.md +0 -71
  139. data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-02-SUMMARY.md +0 -16
  140. data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-02.md +0 -56
  141. data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-03-SUMMARY.md +0 -17
  142. data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-03.md +0 -98
  143. data/.vbw-planning/phases/02-test-performance/.context-dev.md +0 -75
  144. data/.vbw-planning/phases/02-test-performance/.context-lead.md +0 -89
  145. data/.vbw-planning/phases/02-test-performance/.context-qa.md +0 -23
  146. data/.vbw-planning/phases/02-test-performance/02-RESEARCH.md +0 -56
  147. data/.vbw-planning/phases/02-test-performance/02-VERIFICATION.md +0 -51
  148. data/.vbw-planning/phases/02-test-performance/PLAN-01-SUMMARY.md +0 -37
  149. data/.vbw-planning/phases/02-test-performance/PLAN-01.md +0 -156
  150. data/.vbw-planning/phases/02-test-performance/PLAN-02-SUMMARY.md +0 -33
  151. data/.vbw-planning/phases/02-test-performance/PLAN-02.md +0 -120
  152. data/.vbw-planning/phases/02-test-performance/PLAN-03-SUMMARY.md +0 -30
  153. data/.vbw-planning/phases/02-test-performance/PLAN-03.md +0 -154
  154. data/.vbw-planning/phases/02-test-performance/PLAN-04-SUMMARY.md +0 -28
  155. data/.vbw-planning/phases/02-test-performance/PLAN-04.md +0 -133
@@ -1,82 +0,0 @@
1
- <!-- VBW STATE TEMPLATE (ARTF-05) -- Session dashboard, auto-updated -->
2
- <!-- Updated after each plan completion and at checkpoints -->
3
-
4
- # Project State
5
-
6
- ## Project Reference
7
-
8
- See: .vbw-planning/PROJECT.md (updated 2026-02-09)
9
-
10
- **Core value:** Drop-in Rails engine for feed monitoring, content scraping, and operational dashboards.
11
- **Current focus:** All phases complete
12
-
13
- ## Current Position
14
-
15
- Phase: 4 of 4 (Code Quality & Conventions Cleanup)
16
- Plan: 3 of 3 in current phase
17
- Status: Built
18
- Last activity: 2026-02-10 -- Phase 4 complete (3/3 plans done)
19
-
20
- Progress: [##########] 100%
21
-
22
- ## Codebase Profile
23
-
24
- - **Total source files:** 535
25
- - **Primary language:** Ruby (330 files)
26
- - **Templates:** ERB (48 files)
27
- - **Tests:** 137 test files detected
28
- - **Test suite:** 841 runs, 2776 assertions, 0 failures (up from 473 runs in Phase 1)
29
- - **Coverage:** 86.97% line, 58.84% branch (510 uncovered lines, down from 2117)
30
- - **CI/CD:** GitHub Actions (1 workflow)
31
- - **Docker:** Yes (2 files)
32
- - **Monorepo:** No
33
- - **Stack:** Ruby on Rails 8 engine, Solid Queue, Hotwire, Tailwind CSS, PostgreSQL, Minitest, RuboCop, Brakeman
34
-
35
- ## Accumulated Context
36
-
37
- ### Decisions
38
-
39
- - [bootstrap]: Focus on coverage + refactoring before new features
40
- - [bootstrap]: Keep PostgreSQL-only for now
41
- - [bootstrap]: Keep host-app auth model
42
- - [phase-1]: Omakase RuboCop config only enables 45/775 cops; all Metrics cops disabled
43
- - [phase-1]: No .rubocop.yml exclusions needed for large files (Metrics cops off)
44
- - [phase-2]: PG parallel fork segfault when running single test files; use PARALLEL_WORKERS=1 or full suite
45
- - [phase-2]: Configuration tests (Plan 03) were committed under mislabeled "dev-plan05" commit; corrected in summaries
46
- - [phase-3]: FeedFetcher extraction (Plan 01) was committed under mislabeled "plan-04" commit (2f00274); corrected in summaries
47
- - [phase-3]: Ruby autoload used instead of Zeitwerk for lib/ modules -- safest drop-in replacement for eager requires
48
- - [phase-3]: 11 boot-critical requires kept explicit; 71 autoload declarations replace 66 eager requires
49
- - [phase-4]: ItemCreator extracted from 601 to 174 lines (EntryParser + ContentExtractor sub-modules)
50
- - [phase-4]: Fix-everything approach for public API convention violations
51
- - [phase-4]: 3 files slightly exceed 300 lines (entry_parser 390, queries 356, application_helper 346) -- all single-responsibility, cannot be split further
52
-
53
-
54
- None
55
-
56
- ### Blockers/Concerns
57
-
58
- None
59
-
60
- ### Skills
61
-
62
- **Installed:**
63
- - agent-browser (global)
64
- - flowdeck (global)
65
- - ralph-tui-create-json (global)
66
- - ralph-tui-prd (global)
67
- - vastai (global)
68
- - find-skills (global)
69
-
70
- **Suggested (not installed):**
71
- - dhh-rails-style (registry) -- DHH-style Rails conventions
72
- - ruby-rails (registry) -- Ruby on Rails development
73
- - github-actions (registry) -- GitHub Actions workflow
74
-
75
- **Stack detected:** Ruby on Rails 8 engine, Solid Queue, Hotwire (Turbo + Stimulus), Tailwind CSS, PostgreSQL, ESLint, GitHub Actions, Minitest, RuboCop, Brakeman
76
- **Registry available:** yes
77
-
78
- ## Session Continuity
79
-
80
- Last session: 2026-02-10
81
- Stopped at: All 4 phases complete
82
- Resume file: none
@@ -1,56 +0,0 @@
1
- # PLAN-01 Summary: frozen-string-literal-audit
2
-
3
- ## Status: COMPLETE
4
-
5
- ## Commit
6
-
7
- - **Hash:** `5f02db8`
8
- - **Message:** `style(frozen-string-literal): add pragma to all Ruby files`
9
- - **Files changed:** 113 files, 223 insertions
10
-
11
- ## Tasks Completed
12
-
13
- ### Task 1: Add frozen_string_literal to app/ and lib/ source files
14
- - Added pragma to all 29 app/ and lib/ `.rb` files
15
- - No shebang lines encountered in any files
16
-
17
- ### Task 2: Add frozen_string_literal to config and migration files
18
- - Added pragma to `config/routes.rb` and 4 migration files
19
-
20
- ### Task 3: Add frozen_string_literal to test files (excluding test/dummy and test/tmp)
21
- - Added pragma to all 43 test `.rb` files
22
- - `test/test_helper.rb` had no shebang, straightforward prepend
23
-
24
- ### Task 4: Add frozen_string_literal to test/dummy files
25
- - Added pragma to all 22 dummy app `.rb` files
26
-
27
- ### Task 5: Validate full codebase compliance and run tests
28
- - `git ls-files -- '*.rb' | ... | grep -cv 'frozen_string_literal: true'` returns **0**
29
- - `bin/rubocop --only Style/FrozenStringLiteralComment` exits **0** (341 files, no offenses)
30
- - `bin/rails test` passes: **473 runs, 1927 assertions, 0 failures, 0 errors**
31
-
32
- ## Deviations
33
-
34
- ### DEVN-02: Non-.rb Ruby files also needed the pragma (14 additional files)
35
-
36
- The plan scoped only `.rb` files, but the success criterion requires `bin/rubocop --only Style/FrozenStringLiteralComment` to pass. RuboCop also inspects non-`.rb` Ruby files: `Gemfile`, `Rakefile`, `source_monitor.gemspec`, 3 `.rake` files, `test/dummy/Gemfile`, `test/dummy/Rakefile`, 5 `test/dummy/bin/*` scripts, and `test/dummy/config.ru`. All 14 were given the pragma.
37
-
38
- ### DEVN-02: test/tmp/ excluded from RuboCop
39
-
40
- RuboCop was scanning 179 files under `test/tmp/` (untracked generated host app templates) which all lacked the pragma. Since these are not git-tracked and are generated artifacts, added `test/tmp/**/*` to `.rubocop.yml` AllCops Exclude list rather than modifying generated files.
41
-
42
- ### DEVN-01: Shebang handling for bin scripts
43
-
44
- Five `test/dummy/bin/*` files had shebang lines. The pragma was correctly inserted after the shebang on line 2. Two files (`bin/dev`, `bin/jobs`) had a blank line between the shebang and the first require, which would have created a double blank line; these were cleaned up to have a single blank line separator.
45
-
46
- ## Decisions
47
-
48
- 1. **Included non-.rb Ruby files** -- To satisfy the RuboCop success criterion, all Ruby-like files RuboCop inspects needed the pragma, not just `.rb` files.
49
- 2. **Excluded test/tmp/ from RuboCop** -- These are generated Rails app templates that are not git-tracked and should not be linted. This is a minimal `.rubocop.yml` change.
50
- 3. **Did not modify test/lib/tmp/install_generator/config/routes.rb** -- This file is not git-tracked (despite the path existing on disk from a previous test run), so it was left as-is.
51
-
52
- ## Success Criteria
53
-
54
- - [x] Every git-tracked `.rb` file has `# frozen_string_literal: true` (REQ-13)
55
- - [x] RuboCop `Style/FrozenStringLiteralComment` cop passes with zero offenses
56
- - [x] No test regressions introduced (473 tests, 0 failures)
@@ -1,187 +0,0 @@
1
- ---
2
- phase: 1
3
- plan: 1
4
- title: frozen-string-literal-audit
5
- wave: 1
6
- depends_on: []
7
- skills_used: []
8
- must_haves:
9
- truths:
10
- - "Every git-tracked `.rb` file begins with `# frozen_string_literal: true` as its first line (verified by `git ls-files -- '*.rb' | xargs head -1 | grep -cv 'frozen_string_literal: true'` returning 0)"
11
- - "`bin/rubocop --only Style/FrozenStringLiteralComment` exits 0 with zero offenses"
12
- - "All existing tests pass (`bin/rails test` exits 0)"
13
- artifacts:
14
- - "98 Ruby files modified to add the `# frozen_string_literal: true` pragma"
15
- key_links:
16
- - "REQ-13 fully satisfied by this plan"
17
- ---
18
-
19
- # Plan 01: frozen-string-literal-audit
20
-
21
- ## Objective
22
-
23
- Add the `# frozen_string_literal: true` magic comment to every git-tracked Ruby file that is currently missing it. This is a mechanical, low-risk change that brings the codebase into full compliance with REQ-13 and prepares for the RuboCop audit in Plan 02.
24
-
25
- ## Context
26
-
27
- <context>
28
- @.vbw-planning/REQUIREMENTS.md -- REQ-13: frozen_string_literal consistency
29
- @.vbw-planning/codebase/CONVENTIONS.md -- documents existing frozen_string_literal convention
30
- @.rubocop.yml -- RuboCop configuration (omakase base)
31
-
32
- **Decomposition rationale:** This plan is separated from the RuboCop audit because (a) frozen_string_literal changes touch nearly 100 files and are purely mechanical, making them ideal for a single focused commit, and (b) completing this first removes a large category of RuboCop violations, simplifying Plan 02's scope.
33
-
34
- **Current state:**
35
- - 325 git-tracked Ruby files total
36
- - 227 already have `# frozen_string_literal: true`
37
- - 98 are missing it
38
- - Missing files span: app/ (5), lib/ (24 including setup/, engine, version, assets), test/ (43 non-dummy test files), test/dummy/ (22), config/ (1), db/migrate/ (4)
39
- - The codebase convention (per CONVENTIONS.md) is to use frozen_string_literal consistently, but it has drifted in setup/, engine infrastructure, test files, and dummy app files
40
-
41
- **Constraints:**
42
- - Do NOT modify files under `test/tmp/` (generated artifacts, not tracked in git)
43
- - The `test/lib/tmp/install_generator/config/initializers/source_monitor.rb` already has the pragma (verified)
44
- - Migration files and config/routes.rb need the pragma too
45
- - Some files may have a shebang line (`#!/usr/bin/env ruby`) as line 1 -- the pragma must go AFTER the shebang
46
- - `test/dummy/db/schema.rb` is excluded from RuboCop in `.rubocop.yml` but should still get the pragma for consistency
47
- </context>
48
-
49
- ## Tasks
50
-
51
- ### Task 1: Add frozen_string_literal to app/ and lib/ source files
52
-
53
- - **name:** add-frozen-pragma-to-source-files
54
- - **files:**
55
- - `app/controllers/source_monitor/application_controller.rb`
56
- - `app/controllers/source_monitor/health_controller.rb`
57
- - `app/helpers/source_monitor/application_helper.rb`
58
- - `app/jobs/source_monitor/application_job.rb`
59
- - `app/models/source_monitor/application_record.rb`
60
- - `lib/source_monitor.rb`
61
- - `lib/source_monitor/assets.rb`
62
- - `lib/source_monitor/assets/bundler.rb`
63
- - `lib/source_monitor/engine.rb`
64
- - `lib/source_monitor/version.rb`
65
- - `lib/source_monitor/setup/initializer_patcher.rb`
66
- - `lib/source_monitor/setup/bundle_installer.rb`
67
- - `lib/source_monitor/setup/workflow.rb`
68
- - `lib/source_monitor/setup/gemfile_editor.rb`
69
- - `lib/source_monitor/setup/requirements.rb`
70
- - `lib/source_monitor/setup/detectors.rb`
71
- - `lib/source_monitor/setup/shell_runner.rb`
72
- - `lib/source_monitor/setup/cli.rb`
73
- - `lib/source_monitor/setup/verification/printer.rb`
74
- - `lib/source_monitor/setup/verification/telemetry_logger.rb`
75
- - `lib/source_monitor/setup/verification/solid_queue_verifier.rb`
76
- - `lib/source_monitor/setup/verification/result.rb`
77
- - `lib/source_monitor/setup/verification/action_cable_verifier.rb`
78
- - `lib/source_monitor/setup/verification/runner.rb`
79
- - `lib/source_monitor/setup/install_generator.rb`
80
- - `lib/source_monitor/setup/dependency_checker.rb`
81
- - `lib/source_monitor/setup/prompter.rb`
82
- - `lib/source_monitor/setup/migration_installer.rb`
83
- - `lib/source_monitor/setup/node_installer.rb`
84
- - **action:** Prepend `# frozen_string_literal: true\n\n` to each file listed above. If the file already begins with a shebang (`#!`), insert the pragma on line 2 (after the shebang) with a blank line separating them. For `lib/source_monitor.rb` specifically, note it starts with `require` statements -- the pragma goes before all requires.
85
- - **verify:** Run `grep -cL 'frozen_string_literal: true' app/**/*.rb lib/**/*.rb` returns no results (all files have the pragma). Additionally run `ruby -c lib/source_monitor.rb` to confirm syntax validity.
86
- - **done:** All 29 app/ and lib/ Ruby files have `# frozen_string_literal: true` as their first non-shebang line.
87
-
88
- ### Task 2: Add frozen_string_literal to config and migration files
89
-
90
- - **name:** add-frozen-pragma-to-config-and-migrations
91
- - **files:**
92
- - `config/routes.rb`
93
- - `db/migrate/20251009103000_add_feed_content_readability_to_sources.rb`
94
- - `db/migrate/20251014171659_add_performance_indexes.rb`
95
- - `db/migrate/20251014172525_add_fetch_status_check_constraint.rb`
96
- - `db/migrate/20251108120116_refresh_fetch_status_constraint.rb`
97
- - **action:** Prepend `# frozen_string_literal: true\n\n` to each file. These are small files (migration class definitions and route definitions).
98
- - **verify:** Run `head -1` on each file to confirm the pragma is present. Run `ruby -c config/routes.rb` to confirm syntax validity (it will fail since it references SourceMonitor::Engine, so instead just visually confirm the pragma is on line 1).
99
- - **done:** All 5 config/ and db/migrate/ files have the pragma.
100
-
101
- ### Task 3: Add frozen_string_literal to test files (excluding test/dummy and test/tmp)
102
-
103
- - **name:** add-frozen-pragma-to-test-files
104
- - **files:**
105
- - `test/test_helper.rb`
106
- - `test/source_monitor_test.rb`
107
- - `test/gemspec_test.rb`
108
- - `test/application_system_test_case.rb`
109
- - `test/system/dropdown_fallback_test.rb`
110
- - `test/integration/engine_mounting_test.rb`
111
- - `test/integration/navigation_test.rb`
112
- - `test/controllers/source_monitor/health_controller_test.rb`
113
- - `test/jobs/source_monitor/fetch_feed_job_test.rb`
114
- - `test/jobs/source_monitor/item_cleanup_job_test.rb`
115
- - `test/jobs/source_monitor/log_cleanup_job_test.rb`
116
- - All files under `test/lib/source_monitor/setup/` (12 files)
117
- - All files under `test/lib/source_monitor/setup/verification/` (5 files)
118
- - `test/lib/source_monitor/instrumentation_test.rb`
119
- - `test/lib/source_monitor/feedjira_configuration_test.rb`
120
- - `test/lib/source_monitor/metrics_test.rb`
121
- - `test/lib/source_monitor/scheduler_test.rb`
122
- - `test/lib/source_monitor/release/runner_test.rb`
123
- - `test/lib/source_monitor/release/changelog_test.rb`
124
- - `test/lib/source_monitor/items/item_creator_test.rb`
125
- - `test/lib/source_monitor/items/retention_pruner_test.rb`
126
- - `test/lib/source_monitor/events/event_system_test.rb`
127
- - `test/lib/source_monitor/assets/bundler_test.rb`
128
- - `test/lib/source_monitor/engine_assets_configuration_test.rb`
129
- - `test/lib/source_monitor/http_test.rb`
130
- - `test/lib/source_monitor/fetching/feed_fetcher_test.rb`
131
- - `test/lib/source_monitor/fetching/fetch_runner_test.rb`
132
- - **action:** Prepend `# frozen_string_literal: true\n\n` to each file. The `test/test_helper.rb` file may have a shebang or special first lines -- check and handle accordingly.
133
- - **verify:** Run `find test -name '*.rb' -not -path 'test/tmp/*' -not -path 'test/dummy/*' -exec head -1 {} \; | grep -cv 'frozen_string_literal'` returns 0.
134
- - **done:** All 43 test files (excluding dummy and tmp) have the pragma.
135
-
136
- ### Task 4: Add frozen_string_literal to test/dummy files
137
-
138
- - **name:** add-frozen-pragma-to-dummy-app
139
- - **files:**
140
- - `test/dummy/app/controllers/application_controller.rb`
141
- - `test/dummy/app/controllers/test_support_controller.rb`
142
- - `test/dummy/app/helpers/application_helper.rb`
143
- - `test/dummy/app/jobs/application_job.rb`
144
- - `test/dummy/app/mailers/application_mailer.rb`
145
- - `test/dummy/app/models/application_record.rb`
146
- - `test/dummy/app/models/user.rb`
147
- - `test/dummy/config/application.rb`
148
- - `test/dummy/config/boot.rb`
149
- - `test/dummy/config/environment.rb`
150
- - `test/dummy/config/environments/development.rb`
151
- - `test/dummy/config/environments/production.rb`
152
- - `test/dummy/config/environments/test.rb`
153
- - `test/dummy/config/importmap.rb`
154
- - `test/dummy/config/puma.rb`
155
- - `test/dummy/config/routes.rb`
156
- - `test/dummy/config/initializers/assets.rb`
157
- - `test/dummy/config/initializers/content_security_policy.rb`
158
- - `test/dummy/config/initializers/filter_parameter_logging.rb`
159
- - `test/dummy/config/initializers/inflections.rb`
160
- - `test/dummy/db/migrate/20251124080000_create_users.rb`
161
- - `test/dummy/db/schema.rb`
162
- - **action:** Prepend `# frozen_string_literal: true\n\n` to each file. The `test/dummy/db/schema.rb` may be auto-generated by Rails -- still add the pragma since it is git-tracked and part of the project.
163
- - **verify:** Run `find test/dummy -name '*.rb' -exec head -1 {} \; | grep -cv 'frozen_string_literal'` returns 0.
164
- - **done:** All 22 dummy app Ruby files have the pragma.
165
-
166
- ### Task 5: Validate full codebase compliance and run tests
167
-
168
- - **name:** validate-frozen-pragma-compliance
169
- - **files:** (no files modified -- validation only)
170
- - **action:** Run three verification commands: (1) Count git-tracked Ruby files without the pragma -- must be 0. (2) Run `bin/rubocop --only Style/FrozenStringLiteralComment` to confirm zero RuboCop offenses for this cop. (3) Run the test suite to confirm no regressions from adding the pragma.
171
- - **verify:**
172
- - `git ls-files -- '*.rb' | xargs head -1 | grep -cv 'frozen_string_literal: true'` outputs `0`
173
- - `bin/rubocop --only Style/FrozenStringLiteralComment` exits 0
174
- - `bin/rails test` exits 0 (or at minimum no new failures)
175
- - **done:** Full codebase compliance confirmed. REQ-13 is satisfied.
176
-
177
- ## Verification
178
-
179
- 1. `git ls-files -- '*.rb' | xargs head -1 | grep -cv 'frozen_string_literal: true'` returns `0`
180
- 2. `bin/rubocop --only Style/FrozenStringLiteralComment` exits 0 with zero offenses
181
- 3. Test suite passes with no regressions
182
-
183
- ## Success Criteria
184
-
185
- - [x] Every git-tracked Ruby file has `# frozen_string_literal: true` (REQ-13)
186
- - [x] RuboCop `Style/FrozenStringLiteralComment` cop passes with zero offenses
187
- - [x] No test regressions introduced
@@ -1,64 +0,0 @@
1
- # Plan 02 Summary: rubocop-audit-and-fix
2
-
3
- ## Status: complete
4
-
5
- ## Result
6
-
7
- The codebase already passes RuboCop with zero offenses against the `rubocop-rails-omakase` ruleset. No code changes were required.
8
-
9
- ## Tasks Completed
10
-
11
- | Task | Name | Result |
12
- |------|------|--------|
13
- | 1 | rubocop-audit-categorize-violations | 341 files inspected, 0 offenses |
14
- | 2 | apply-safe-rubocop-autocorrect | No-op (no violations to fix) |
15
- | 3 | fix-remaining-rubocop-violations | No-op (no violations to fix) |
16
- | 4 | configure-rubocop-exclusions-for-phase3 | No-op (Metrics cops disabled in omakase) |
17
- | 5 | validate-rubocop-zero-offenses | All checks pass |
18
-
19
- ## Violation Counts
20
-
21
- - **Before:** 0 offenses (341 files inspected)
22
- - **After:** 0 offenses (341 files inspected)
23
-
24
- ## Commit
25
-
26
- No commit created -- no code changes were needed.
27
-
28
- ## Verification Results
29
-
30
- | Check | Result |
31
- |-------|--------|
32
- | `bin/rubocop -f simple` | 341 files inspected, no offenses detected |
33
- | `bin/rubocop -f github` | Exit 0 |
34
- | `bin/rails test` | 473 runs, 1927 assertions, 0 failures, 0 errors, 0 skips |
35
- | Coverage baseline (`config/coverage_baseline.json`) | 2328 lines (unchanged) |
36
-
37
- ## Key Findings
38
-
39
- 1. **Omakase config is minimal by design.** The `rubocop-rails-omakase` gem enables only 45 cops (out of 775 available). It focuses on essential layout and style rules, not metrics or complex analysis.
40
-
41
- 2. **Metrics cops are all disabled.** `Metrics/ClassLength`, `Metrics/MethodLength`, `Metrics/BlockLength`, and all other Metrics cops are set to `Enabled: false` in the omakase config. This means the large files (FeedFetcher 627 lines, Configuration 655 lines, ImportSessionsController 792 lines) do not trigger any violations. No `.rubocop.yml` exclusions were needed.
42
-
43
- 3. **Plan 01 was the key enabler.** The frozen_string_literal pragma work (Plan 01, commit 5f02db8, 113 files) was likely the primary source of violations. After that was completed, the remaining code was already compliant with the 45 enabled cops.
44
-
45
- 4. **Enabled cop categories:**
46
- - Layout (27 cops): indentation, spacing, whitespace
47
- - Style (12 cops): string literals, hash syntax, parentheses, semicolons
48
- - Lint (4 cops): string coercion, require parentheses, syntax, URI escape
49
- - Performance (1 cop): flat_map
50
- - Migration (1 cop): department name
51
-
52
- ## Deviations
53
-
54
- | ID | Description | Impact |
55
- |----|-------------|--------|
56
- | DEVN-01 | Tasks 2-4 were no-ops because no violations existed | None -- plan designed for worst case, actual state was already compliant |
57
- | DEVN-01 | No git commit created (no code changes) | None -- the success criteria (zero offenses, tests pass) are satisfied without changes |
58
- | DEVN-01 | No `.rubocop.yml` exclusions added for Phase 3 files | None -- Metrics cops are disabled in omakase, so exclusions would be meaningless |
59
-
60
- ## REQ-14 Status
61
-
62
- **REQ-14 (Audit and fix any RuboCop violations against omakase ruleset): SATISFIED**
63
-
64
- The audit confirms zero violations exist. The CI lint job (`bin/rubocop -f github`) exits 0.
@@ -1,137 +0,0 @@
1
- ---
2
- phase: 1
3
- plan: 2
4
- title: rubocop-audit-and-fix
5
- wave: 2
6
- depends_on: [1]
7
- skills_used: []
8
- must_haves:
9
- truths:
10
- - "`bin/rubocop` exits 0 with zero offenses (verified by `bin/rubocop -f simple` output showing `no offenses detected`)"
11
- - "All existing tests pass (`bin/rails test` exits 0 with no new failures)"
12
- - "CI lint job would pass (`bin/rubocop -f github` exits 0)"
13
- artifacts:
14
- - "All Ruby files in app/, lib/, test/, config/, db/ comply with rubocop-rails-omakase rules"
15
- - "`.rubocop.yml` may have additional targeted exclusions if auto-generated files legitimately violate rules"
16
- key_links:
17
- - "REQ-14 fully satisfied by this plan"
18
- - "Depends on Plan 01 (frozen_string_literal already resolved -- largest category of violations removed)"
19
- ---
20
-
21
- # Plan 02: rubocop-audit-and-fix
22
-
23
- ## Objective
24
-
25
- Audit the entire codebase with RuboCop using the `rubocop-rails-omakase` configuration and fix all violations, achieving zero offenses. This satisfies REQ-14 and ensures the CI lint job passes cleanly.
26
-
27
- ## Context
28
-
29
- <context>
30
- @.vbw-planning/REQUIREMENTS.md -- REQ-14: RuboCop audit against omakase ruleset
31
- @.vbw-planning/codebase/CONVENTIONS.md -- Rails omakase style guide, existing patterns
32
- @.rubocop.yml -- inherits from rubocop-rails-omakase, excludes test/dummy/db/schema.rb
33
- @Gemfile -- rubocop-rails-omakase gem included
34
- @bin/rubocop -- wrapper script that forces config path
35
- @.github/workflows/ci.yml -- lint job runs `bin/rubocop -f github`
36
-
37
- **Decomposition rationale:** This plan depends on Plan 01 because `Style/FrozenStringLiteralComment` is typically the most voluminous cop violation. By completing Plan 01 first, this plan deals with a much smaller and more varied set of violations that require more careful, contextual fixes.
38
-
39
- **Current state:**
40
- - The project uses `rubocop-rails-omakase` as its base ruleset (inherits the gem's rubocop.yml)
41
- - Only one exclusion exists: `test/dummy/db/schema.rb`
42
- - After Plan 01 completes, `Style/FrozenStringLiteralComment` violations will be resolved
43
- - Remaining violations are unknown until the audit is run, but likely categories include:
44
- - `Style/StringLiterals` (single vs double quotes)
45
- - `Layout/*` (indentation, spacing, line length)
46
- - `Metrics/*` (method/class length -- may need exclusions for large files targeted in Phase 3)
47
- - `Naming/*` (variable/method naming conventions)
48
- - `Rails/*` cops from the omakase set
49
- - Large files (FeedFetcher 627 lines, Configuration 655 lines, ImportSessionsController 792 lines) may trigger `Metrics/ClassLength` or `Metrics/MethodLength` -- these should be addressed with targeted `.rubocop.yml` exclusions since Phase 3 handles the actual refactoring
50
-
51
- **Constraints:**
52
- - Fix violations using RuboCop auto-correct where safe (`rubocop -a` for safe corrections, `-A` for aggressive only when reviewed)
53
- - Do NOT refactor large files to satisfy Metrics cops -- instead exclude them in `.rubocop.yml` with a comment referencing Phase 3
54
- - Preserve all existing behavior -- style-only changes
55
- - The `test/dummy/db/schema.rb` exclusion must remain (Rails-generated)
56
- - Test files in `test/tmp/` are not git-tracked and not subject to RuboCop
57
- </context>
58
-
59
- ## Tasks
60
-
61
- ### Task 1: Run RuboCop audit and categorize violations
62
-
63
- - **name:** rubocop-audit-categorize-violations
64
- - **files:** (no files modified -- analysis only)
65
- - **action:** Run `bin/rubocop -f json -o tmp/rubocop_report.json` and `bin/rubocop -f simple` to get a complete picture of all violations. Categorize them by: (a) auto-correctable with `-a` (safe), (b) auto-correctable with `-A` (unsafe, needs review), (c) manual fix required, (d) should be excluded (Metrics cops on large files destined for Phase 3 refactoring). Document the count and category of each cop violation type.
66
- - **verify:** The audit report exists and lists all violations. Categorization is complete.
67
- - **done:** Full understanding of the violation landscape. Clear plan for which files need which type of fix.
68
-
69
- ### Task 2: Apply safe auto-corrections
70
-
71
- - **name:** apply-safe-rubocop-autocorrect
72
- - **files:** All Ruby files flagged by RuboCop safe auto-correct
73
- - **action:** Run `bin/rubocop -a` to apply all safe auto-corrections across the codebase. This handles cops like `Style/StringLiterals`, `Layout/TrailingWhitespace`, `Layout/EmptyLineAfterMagicComment`, `Layout/SpaceInsideBlockBraces`, etc. Review the diff to confirm no behavioral changes -- only formatting/style changes. If any auto-correction looks wrong, revert that specific change and handle it manually in Task 3.
74
- - **verify:** Run `git diff --stat` to see scope of changes. Run `bin/rails test` to confirm no test regressions. Run `bin/rubocop -f simple` to see remaining violations after safe auto-correct.
75
- - **done:** All safe auto-correctable violations are fixed. Test suite still passes.
76
-
77
- ### Task 3: Fix remaining violations manually
78
-
79
- - **name:** fix-remaining-rubocop-violations
80
- - **files:** Files with violations that were not auto-correctable or were unsafe auto-corrections
81
- - **action:** For each remaining violation:
82
- - **Style cops**: Fix manually following the omakase conventions (single quotes for simple strings, double quotes when interpolation needed, etc.)
83
- - **Layout cops**: Fix indentation, spacing, alignment manually
84
- - **Naming cops**: Rename variables/methods to comply (ensure test references are updated)
85
- - **Rails cops**: Fix any Rails-specific violations (e.g., `Rails/HttpPositionalArguments`)
86
- - If a violation is in a file that is inherently non-compliant due to its nature (e.g., a migration with unusual structure), add a targeted inline `# rubocop:disable` comment with an explanation
87
- - **verify:** Run `bin/rubocop -f simple` after each batch of fixes. The violation count should decrease monotonically. Run `bin/rails test` after all manual fixes.
88
- - **done:** All non-Metrics violations are resolved either by code changes or justified inline disables.
89
-
90
- ### Task 4: Configure exclusions for large files (Phase 3 targets)
91
-
92
- - **name:** configure-rubocop-exclusions-for-phase3
93
- - **files:**
94
- - `.rubocop.yml`
95
- - **action:** If `Metrics/ClassLength`, `Metrics/MethodLength`, or `Metrics/BlockLength` violations remain for the three large files targeted for refactoring in Phase 3, add targeted exclusions to `.rubocop.yml`:
96
- ```yaml
97
- # Phase 3 refactoring targets -- remove exclusions after extraction
98
- Metrics/ClassLength:
99
- Exclude:
100
- - "lib/source_monitor/fetching/feed_fetcher.rb"
101
- - "lib/source_monitor/configuration.rb"
102
- - "app/controllers/source_monitor/import_sessions_controller.rb"
103
- ```
104
- Add a comment explaining these are temporary exclusions that will be removed in Phase 3. Do NOT exclude any other files -- only the three identified large files.
105
- - **verify:** Run `bin/rubocop` and confirm it exits 0 with zero offenses. The exclusions should only cover the Phase 3 target files.
106
- - **done:** `.rubocop.yml` has targeted, documented exclusions. Zero RuboCop offenses across the entire codebase.
107
-
108
- ### Task 5: Final validation and CI readiness check
109
-
110
- - **name:** validate-rubocop-zero-offenses
111
- - **files:** (no files modified -- validation only)
112
- - **action:** Run the full validation suite: (1) `bin/rubocop -f simple` -- must show `no offenses detected`. (2) `bin/rubocop -f github` -- must exit 0 (this is what CI runs). (3) `bin/rails test` -- full test suite must pass. (4) Verify the coverage baseline has not grown (run `wc -l config/coverage_baseline.json` and confirm it is still approximately 2328 lines -- style changes should not affect coverage).
113
- - **verify:**
114
- - `bin/rubocop` exits 0
115
- - `bin/rubocop -f github` exits 0
116
- - `bin/rails test` exits 0
117
- - Coverage baseline line count has not increased
118
- - **done:** Zero RuboCop violations. CI-ready. REQ-14 satisfied.
119
-
120
- ## Verification
121
-
122
- 1. `bin/rubocop -f simple` outputs `no offenses detected`
123
- 2. `bin/rubocop -f github` exits 0 (CI lint format)
124
- 3. `bin/rails test` exits 0 with no regressions
125
- 4. Coverage baseline (`config/coverage_baseline.json`) has not grown in line count
126
-
127
- ## Success Criteria
128
-
129
- - [x] Zero RuboCop violations against the omakase ruleset (REQ-14)
130
- - [x] Any `.rubocop.yml` exclusions are limited to Phase 3 target files with documenting comments
131
- - [x] CI lint job (`bin/rubocop -f github`) passes
132
- - [x] No test regressions
133
- - [x] No behavioral changes -- all fixes are style/formatting only
134
-
135
- ## Phase 1 Coverage Note
136
-
137
- Phase 1 success criterion #3 ("Coverage baseline shrinks by at least 10%") is not directly addressed by Plans 01 or 02, which focus on code quality (REQ-13, REQ-14). The coverage baseline may shrink slightly if RuboCop fixes remove dead branches or simplify code paths. After Plan 02 completes, regenerate the baseline with `bin/update-coverage-baseline` and measure the delta. The 10% reduction target (from 2328 uncovered lines to ~2095 or fewer) will primarily be achieved in Phase 2 when dedicated test coverage plans execute.
@@ -1,67 +0,0 @@
1
- # PLAN-01 Summary: feed-fetcher-tests
2
-
3
- ## Status: COMPLETE
4
-
5
- ## Commit
6
-
7
- - **Hash:** `8d4e8d3`
8
- - **Message:** `test(feed-fetcher): close coverage gaps for retry, errors, headers, entries, helpers [dev-plan01]`
9
- - **Files changed:** 1 file, 734 insertions
10
-
11
- ## Tasks Completed
12
-
13
- ### Task 1: Test retry strategy and circuit breaker transitions
14
- - Added tests for reset_retry_state!, apply_retry_strategy!, circuit breaker open/close
15
- - Verified first timeout sets fetch_retry_attempt to 1
16
- - Verified exhausting retries opens circuit (sets fetch_circuit_opened_at, fetch_circuit_until)
17
- - Verified successful fetch resets retry state
18
- - Tested RetryPolicy error handling fallback
19
-
20
- ### Task 2: Test Faraday error wrapping and connection failures
21
- - Tested Faraday::ConnectionFailed raises ConnectionError with original_error preserved
22
- - Tested Faraday::SSLError raises ConnectionError
23
- - Tested Faraday::ClientError with response hash builds HTTPError via build_http_error_from_faraday
24
- - Tested generic Faraday::Error raises FetchError
25
- - Tested non-Faraday StandardError wrapped in UnexpectedResponseError
26
-
27
- ### Task 3: Test Last-Modified header handling and request headers
28
- - Tested If-Modified-Since header sent when source.last_modified is set
29
- - Tested Last-Modified response header parsed and stored on source
30
- - Tested malformed Last-Modified headers silently ignored
31
- - Tested custom_headers from source passed through to request
32
- - Tested ETag and Last-Modified preserved on 304 responses
33
-
34
- ### Task 4: Test entry processing edge cases and error normalization
35
- - Tested feed without entries returns zero counts
36
- - Tested Events.run_item_processors called for each entry
37
- - Tested Events.after_item_created called only for created items
38
- - Tested normalize_item_error extracts guid via entry_id/id fallbacks
39
- - Tested safe_entry_title returns nil for entries without title
40
-
41
- ### Task 5: Test jitter, interval helpers, and metadata management
42
- - Tested jitter_offset returns 0 when interval_seconds <= 0
43
- - Tested jitter_offset uses jitter_proc when provided
44
- - Tested body_digest returns nil for blank body, SHA256 for non-blank
45
- - Tested updated_metadata preserves existing metadata
46
- - Tested configured_seconds, extract_numeric edge cases
47
-
48
- ## Deviations
49
-
50
- None -- plan executed as specified.
51
-
52
- ## Verification Results
53
-
54
- | Check | Result |
55
- |-------|--------|
56
- | `bin/rails test test/lib/source_monitor/fetching/feed_fetcher_test.rb` | All tests pass |
57
- | `bin/rails test` | 760 runs, 2626 assertions, 0 failures, 0 errors, 0 skips |
58
-
59
- ## Success Criteria
60
-
61
- - [x] 48 new tests added (734 lines)
62
- - [x] All retry/circuit breaker branches tested
63
- - [x] All Faraday error wrapping branches tested
64
- - [x] All header handling branches tested
65
- - [x] Entry processing and error normalization branches tested
66
- - [x] Jitter, interval helpers, and metadata management tested
67
- - [x] REQ-01 substantially satisfied