source_monitor 0.2.1 → 0.3.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 (228) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/agents/rails-concern.md +464 -0
  3. data/.claude/agents/rails-controller.md +424 -0
  4. data/.claude/agents/rails-hotwire.md +446 -0
  5. data/.claude/agents/rails-implement.md +374 -0
  6. data/.claude/agents/rails-job.md +334 -0
  7. data/.claude/agents/rails-lint.md +294 -0
  8. data/.claude/agents/rails-mailer.md +371 -0
  9. data/.claude/agents/rails-migration.md +449 -0
  10. data/.claude/agents/rails-model.md +420 -0
  11. data/.claude/agents/rails-policy.md +443 -0
  12. data/.claude/agents/rails-presenter.md +427 -0
  13. data/.claude/agents/rails-query.md +412 -0
  14. data/.claude/agents/rails-review.md +490 -0
  15. data/.claude/agents/rails-service.md +458 -0
  16. data/.claude/agents/rails-state-records.md +465 -0
  17. data/.claude/agents/rails-tdd.md +314 -0
  18. data/.claude/agents/rails-test.md +441 -0
  19. data/.claude/agents/rails-view-component.md +418 -0
  20. data/.claude/hooks/block-secrets.sh +52 -0
  21. data/.claude/settings.json +85 -0
  22. data/.claude/skills/action-cable-patterns/SKILL.md +296 -0
  23. data/.claude/skills/action-mailer-patterns/SKILL.md +295 -0
  24. data/.claude/skills/active-storage-setup/SKILL.md +311 -0
  25. data/.claude/skills/api-versioning/SKILL.md +294 -0
  26. data/.claude/skills/authentication-flow/SKILL.md +335 -0
  27. data/.claude/skills/authentication-flow/reference/current.md +248 -0
  28. data/.claude/skills/authentication-flow/reference/passwordless.md +253 -0
  29. data/.claude/skills/authentication-flow/reference/sessions.md +201 -0
  30. data/.claude/skills/authorization-pundit/SKILL.md +462 -0
  31. data/.claude/skills/caching-strategies/SKILL.md +350 -0
  32. data/.claude/skills/database-migrations/SKILL.md +354 -0
  33. data/.claude/skills/form-object-patterns/SKILL.md +399 -0
  34. data/.claude/skills/hotwire-patterns/SKILL.md +247 -0
  35. data/.claude/skills/hotwire-patterns/reference/stimulus.md +307 -0
  36. data/.claude/skills/hotwire-patterns/reference/tailwind-integration.md +112 -0
  37. data/.claude/skills/hotwire-patterns/reference/turbo-frames.md +158 -0
  38. data/.claude/skills/hotwire-patterns/reference/turbo-streams.md +218 -0
  39. data/.claude/skills/i18n-patterns/SKILL.md +320 -0
  40. data/.claude/skills/install/SKILL.md +367 -0
  41. data/.claude/skills/performance-optimization/SKILL.md +311 -0
  42. data/.claude/skills/rails-architecture/SKILL.md +259 -0
  43. data/.claude/skills/rails-architecture/reference/error-handling.md +333 -0
  44. data/.claude/skills/rails-architecture/reference/event-tracking.md +142 -0
  45. data/.claude/skills/rails-architecture/reference/layer-interactions.md +417 -0
  46. data/.claude/skills/rails-architecture/reference/multi-tenancy.md +152 -0
  47. data/.claude/skills/rails-architecture/reference/query-patterns.md +342 -0
  48. data/.claude/skills/rails-architecture/reference/service-patterns.md +286 -0
  49. data/.claude/skills/rails-architecture/reference/state-records.md +250 -0
  50. data/.claude/skills/rails-architecture/reference/testing-strategy.md +326 -0
  51. data/.claude/skills/rails-concern/SKILL.md +399 -0
  52. data/.claude/skills/rails-controller/SKILL.md +336 -0
  53. data/.claude/skills/rails-model-generator/SKILL.md +321 -0
  54. data/.claude/skills/rails-model-generator/reference/validations.md +298 -0
  55. data/.claude/skills/rails-presenter/SKILL.md +274 -0
  56. data/.claude/skills/rails-query-object/SKILL.md +289 -0
  57. data/.claude/skills/rails-service-object/SKILL.md +349 -0
  58. data/.claude/skills/sm-architecture/SKILL.md +233 -0
  59. data/.claude/skills/sm-architecture/reference/extraction-patterns.md +192 -0
  60. data/.claude/skills/sm-architecture/reference/module-map.md +194 -0
  61. data/.claude/skills/sm-configuration-setting/SKILL.md +264 -0
  62. data/.claude/skills/sm-configuration-setting/reference/settings-catalog.md +248 -0
  63. data/.claude/skills/sm-configuration-setting/reference/settings-pattern.md +297 -0
  64. data/.claude/skills/sm-configure/SKILL.md +153 -0
  65. data/.claude/skills/sm-configure/reference/configuration-reference.md +321 -0
  66. data/.claude/skills/sm-dashboard-widget/SKILL.md +344 -0
  67. data/.claude/skills/sm-dashboard-widget/reference/dashboard-patterns.md +304 -0
  68. data/.claude/skills/sm-domain-model/SKILL.md +188 -0
  69. data/.claude/skills/sm-domain-model/reference/model-graph.md +114 -0
  70. data/.claude/skills/sm-domain-model/reference/table-structure.md +348 -0
  71. data/.claude/skills/sm-engine-migration/SKILL.md +395 -0
  72. data/.claude/skills/sm-engine-migration/reference/migration-conventions.md +255 -0
  73. data/.claude/skills/sm-engine-test/SKILL.md +302 -0
  74. data/.claude/skills/sm-engine-test/reference/test-helpers.md +259 -0
  75. data/.claude/skills/sm-engine-test/reference/test-patterns.md +411 -0
  76. data/.claude/skills/sm-event-handler/SKILL.md +265 -0
  77. data/.claude/skills/sm-event-handler/reference/events-api.md +229 -0
  78. data/.claude/skills/sm-health-rule/SKILL.md +327 -0
  79. data/.claude/skills/sm-health-rule/reference/health-system.md +269 -0
  80. data/.claude/skills/sm-host-setup/SKILL.md +223 -0
  81. data/.claude/skills/sm-host-setup/reference/initializer-template.md +195 -0
  82. data/.claude/skills/sm-host-setup/reference/setup-checklist.md +134 -0
  83. data/.claude/skills/sm-job/SKILL.md +263 -0
  84. data/.claude/skills/sm-job/reference/job-conventions.md +245 -0
  85. data/.claude/skills/sm-model-extension/SKILL.md +287 -0
  86. data/.claude/skills/sm-model-extension/reference/extension-api.md +317 -0
  87. data/.claude/skills/sm-pipeline-stage/SKILL.md +254 -0
  88. data/.claude/skills/sm-pipeline-stage/reference/completion-handlers.md +152 -0
  89. data/.claude/skills/sm-pipeline-stage/reference/entry-processing.md +191 -0
  90. data/.claude/skills/sm-pipeline-stage/reference/feed-fetcher-architecture.md +198 -0
  91. data/.claude/skills/sm-scraper-adapter/SKILL.md +284 -0
  92. data/.claude/skills/sm-scraper-adapter/reference/adapter-contract.md +167 -0
  93. data/.claude/skills/sm-scraper-adapter/reference/example-adapter.md +274 -0
  94. data/.claude/skills/solid-queue-setup/SKILL.md +307 -0
  95. data/.claude/skills/tdd-cycle/SKILL.md +359 -0
  96. data/.claude/skills/viewcomponent-patterns/SKILL.md +333 -0
  97. data/.rubocop.yml +2 -0
  98. data/.ruby-version +1 -1
  99. data/.vbw-planning/.notification-log.jsonl +246 -0
  100. data/.vbw-planning/.session-log.jsonl +992 -0
  101. data/.vbw-planning/PROJECT.md +51 -0
  102. data/.vbw-planning/REQUIREMENTS.md +50 -0
  103. data/.vbw-planning/SHIPPED.md +28 -0
  104. data/.vbw-planning/codebase/ARCHITECTURE.md +147 -0
  105. data/.vbw-planning/codebase/CONCERNS.md +99 -0
  106. data/.vbw-planning/codebase/CONVENTIONS.md +97 -0
  107. data/.vbw-planning/codebase/DEPENDENCIES.md +100 -0
  108. data/.vbw-planning/codebase/INDEX.md +86 -0
  109. data/.vbw-planning/codebase/META.md +42 -0
  110. data/.vbw-planning/codebase/PATTERNS.md +262 -0
  111. data/.vbw-planning/codebase/STACK.md +101 -0
  112. data/.vbw-planning/codebase/STRUCTURE.md +324 -0
  113. data/.vbw-planning/codebase/TESTING.md +154 -0
  114. data/.vbw-planning/config.json +12 -0
  115. data/.vbw-planning/discovery.json +24 -0
  116. data/.vbw-planning/milestones/default/ROADMAP.md +115 -0
  117. data/.vbw-planning/milestones/default/STATE.md +83 -0
  118. data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-01-SUMMARY.md +56 -0
  119. data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-01.md +187 -0
  120. data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-02-SUMMARY.md +64 -0
  121. data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-02.md +137 -0
  122. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-01-SUMMARY.md +67 -0
  123. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-01.md +142 -0
  124. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-02-SUMMARY.md +64 -0
  125. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-02.md +138 -0
  126. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-03-SUMMARY.md +85 -0
  127. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-03.md +147 -0
  128. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-04-SUMMARY.md +63 -0
  129. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-04.md +129 -0
  130. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-05-SUMMARY.md +74 -0
  131. data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-05.md +154 -0
  132. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/03-VERIFICATION-wave1.md +303 -0
  133. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/03-VERIFICATION.md +510 -0
  134. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-01-SUMMARY.md +61 -0
  135. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-01.md +161 -0
  136. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-02-SUMMARY.md +66 -0
  137. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-02.md +132 -0
  138. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-03-SUMMARY.md +59 -0
  139. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-03.md +171 -0
  140. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-04-SUMMARY.md +56 -0
  141. data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-04.md +152 -0
  142. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/04-CONTEXT.md +33 -0
  143. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-01-SUMMARY.md +42 -0
  144. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-01.md +119 -0
  145. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-02-SUMMARY.md +52 -0
  146. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-02.md +195 -0
  147. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-03-SUMMARY.md +79 -0
  148. data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-03.md +130 -0
  149. data/CHANGELOG.md +37 -0
  150. data/CLAUDE.md +222 -0
  151. data/Gemfile +8 -0
  152. data/Gemfile.lock +132 -120
  153. data/Rakefile +2 -0
  154. data/app/controllers/source_monitor/application_controller.rb +2 -0
  155. data/app/controllers/source_monitor/health_controller.rb +2 -0
  156. data/app/controllers/source_monitor/import_sessions/bulk_configuration.rb +106 -0
  157. data/app/controllers/source_monitor/import_sessions/entry_annotation.rb +187 -0
  158. data/app/controllers/source_monitor/import_sessions/health_check_management.rb +112 -0
  159. data/app/controllers/source_monitor/import_sessions/opml_parser.rb +130 -0
  160. data/app/controllers/source_monitor/import_sessions_controller.rb +6 -507
  161. data/app/controllers/source_monitor/items_controller.rb +2 -0
  162. data/app/controllers/source_monitor/sources_controller.rb +0 -14
  163. data/app/helpers/source_monitor/application_helper.rb +4 -112
  164. data/app/helpers/source_monitor/health_badge_helper.rb +69 -0
  165. data/app/helpers/source_monitor/table_sort_helper.rb +53 -0
  166. data/app/jobs/source_monitor/application_job.rb +2 -0
  167. data/app/models/source_monitor/application_record.rb +2 -0
  168. data/app/models/source_monitor/log_entry.rb +0 -2
  169. data/config/coverage_baseline.json +217 -1862
  170. data/config/routes.rb +2 -0
  171. data/db/migrate/20251009103000_add_feed_content_readability_to_sources.rb +2 -0
  172. data/db/migrate/20251014171659_add_performance_indexes.rb +2 -0
  173. data/db/migrate/20251014172525_add_fetch_status_check_constraint.rb +2 -0
  174. data/db/migrate/20251108120116_refresh_fetch_status_constraint.rb +2 -0
  175. data/db/migrate/20260210204022_add_composite_index_to_log_entries.rb +17 -0
  176. data/lib/source_monitor/assets/bundler.rb +2 -0
  177. data/lib/source_monitor/assets.rb +2 -0
  178. data/lib/source_monitor/configuration/authentication_settings.rb +62 -0
  179. data/lib/source_monitor/configuration/events.rb +60 -0
  180. data/lib/source_monitor/configuration/fetching_settings.rb +27 -0
  181. data/lib/source_monitor/configuration/health_settings.rb +27 -0
  182. data/lib/source_monitor/configuration/http_settings.rb +43 -0
  183. data/lib/source_monitor/configuration/model_definition.rb +108 -0
  184. data/lib/source_monitor/configuration/models.rb +36 -0
  185. data/lib/source_monitor/configuration/realtime_settings.rb +95 -0
  186. data/lib/source_monitor/configuration/retention_settings.rb +45 -0
  187. data/lib/source_monitor/configuration/scraper_registry.rb +67 -0
  188. data/lib/source_monitor/configuration/scraping_settings.rb +39 -0
  189. data/lib/source_monitor/configuration/validation_definition.rb +32 -0
  190. data/lib/source_monitor/configuration.rb +12 -579
  191. data/lib/source_monitor/dashboard/queries/recent_activity_query.rb +138 -0
  192. data/lib/source_monitor/dashboard/queries/stats_query.rb +71 -0
  193. data/lib/source_monitor/dashboard/queries.rb +2 -195
  194. data/lib/source_monitor/engine.rb +2 -0
  195. data/lib/source_monitor/fetching/feed_fetcher/adaptive_interval.rb +141 -0
  196. data/lib/source_monitor/fetching/feed_fetcher/entry_processor.rb +89 -0
  197. data/lib/source_monitor/fetching/feed_fetcher/source_updater.rb +200 -0
  198. data/lib/source_monitor/fetching/feed_fetcher.rb +37 -379
  199. data/lib/source_monitor/items/item_creator/content_extractor.rb +113 -0
  200. data/lib/source_monitor/items/item_creator/entry_parser/media_extraction.rb +96 -0
  201. data/lib/source_monitor/items/item_creator/entry_parser.rb +294 -0
  202. data/lib/source_monitor/items/item_creator.rb +28 -455
  203. data/lib/source_monitor/setup/bundle_installer.rb +2 -0
  204. data/lib/source_monitor/setup/cli.rb +2 -0
  205. data/lib/source_monitor/setup/dependency_checker.rb +2 -0
  206. data/lib/source_monitor/setup/detectors.rb +2 -0
  207. data/lib/source_monitor/setup/gemfile_editor.rb +2 -0
  208. data/lib/source_monitor/setup/initializer_patcher.rb +2 -0
  209. data/lib/source_monitor/setup/install_generator.rb +2 -0
  210. data/lib/source_monitor/setup/migration_installer.rb +2 -0
  211. data/lib/source_monitor/setup/node_installer.rb +2 -0
  212. data/lib/source_monitor/setup/prompter.rb +2 -0
  213. data/lib/source_monitor/setup/requirements.rb +2 -0
  214. data/lib/source_monitor/setup/shell_runner.rb +2 -0
  215. data/lib/source_monitor/setup/verification/action_cable_verifier.rb +2 -0
  216. data/lib/source_monitor/setup/verification/printer.rb +2 -0
  217. data/lib/source_monitor/setup/verification/result.rb +2 -0
  218. data/lib/source_monitor/setup/verification/runner.rb +2 -0
  219. data/lib/source_monitor/setup/verification/solid_queue_verifier.rb +2 -0
  220. data/lib/source_monitor/setup/verification/telemetry_logger.rb +2 -0
  221. data/lib/source_monitor/setup/workflow.rb +19 -2
  222. data/lib/source_monitor/version.rb +3 -1
  223. data/lib/source_monitor.rb +140 -58
  224. data/lib/tasks/source_monitor_assets.rake +2 -0
  225. data/lib/tasks/source_monitor_setup.rake +60 -0
  226. data/lib/tasks/source_monitor_tasks.rake +2 -0
  227. data/source_monitor.gemspec +4 -1
  228. metadata +177 -4
@@ -0,0 +1,248 @@
1
+ # Configuration Settings Catalog
2
+
3
+ All configuration sections with their attributes, defaults, and types.
4
+
5
+ ## Top-Level Attributes
6
+
7
+ **File:** `lib/source_monitor/configuration.rb`
8
+
9
+ | Attribute | Type | Default | Description |
10
+ |-----------|------|---------|-------------|
11
+ | `queue_namespace` | String | `"source_monitor"` | Namespace prefix for queue names |
12
+ | `fetch_queue_name` | String | `"source_monitor_fetch"` | Queue name for fetch jobs |
13
+ | `scrape_queue_name` | String | `"source_monitor_scrape"` | Queue name for scrape jobs |
14
+ | `fetch_queue_concurrency` | Integer | `2` | Max concurrent fetch workers |
15
+ | `scrape_queue_concurrency` | Integer | `2` | Max concurrent scrape workers |
16
+ | `recurring_command_job_class` | Class/nil | `nil` | Custom recurring job class |
17
+ | `job_metrics_enabled` | Boolean | `true` | Enable job metrics tracking |
18
+ | `mission_control_enabled` | Boolean | `false` | Enable Mission Control integration |
19
+ | `mission_control_dashboard_path` | String/Proc/nil | `nil` | Path or callable for Mission Control |
20
+
21
+ **Methods:**
22
+ - `queue_name_for(:fetch)` / `queue_name_for(:scrape)` -- Returns prefixed queue name
23
+ - `concurrency_for(:fetch)` / `concurrency_for(:scrape)` -- Returns concurrency limit
24
+
25
+ ---
26
+
27
+ ## HTTPSettings
28
+
29
+ **File:** `lib/source_monitor/configuration/http_settings.rb`
30
+
31
+ | Attribute | Type | Default | Description |
32
+ |-----------|------|---------|-------------|
33
+ | `timeout` | Integer | `15` | Total request timeout (seconds) |
34
+ | `open_timeout` | Integer | `5` | Connection open timeout (seconds) |
35
+ | `max_redirects` | Integer | `5` | Max HTTP redirects to follow |
36
+ | `user_agent` | String | `"SourceMonitor/<version>"` | User-Agent header value |
37
+ | `proxy` | String/nil | `nil` | HTTP proxy URL |
38
+ | `headers` | Hash | `{}` | Default HTTP headers |
39
+ | `retry_max` | Integer | `4` | Max retry attempts |
40
+ | `retry_interval` | Float | `0.5` | Base retry interval (seconds) |
41
+ | `retry_interval_randomness` | Float | `0.5` | Retry interval randomness factor |
42
+ | `retry_backoff_factor` | Integer | `2` | Exponential backoff multiplier |
43
+ | `retry_statuses` | Array/nil | `nil` | HTTP statuses to retry on |
44
+
45
+ Has `reset!` method.
46
+
47
+ ---
48
+
49
+ ## FetchingSettings
50
+
51
+ **File:** `lib/source_monitor/configuration/fetching_settings.rb`
52
+
53
+ | Attribute | Type | Default | Description |
54
+ |-----------|------|---------|-------------|
55
+ | `min_interval_minutes` | Integer | `5` | Minimum fetch interval |
56
+ | `max_interval_minutes` | Integer | `1440` (24h) | Maximum fetch interval |
57
+ | `increase_factor` | Float | `1.25` | Multiplier when content unchanged |
58
+ | `decrease_factor` | Float | `0.75` | Multiplier when content changed |
59
+ | `failure_increase_factor` | Float | `1.5` | Multiplier on fetch failure |
60
+ | `jitter_percent` | Float | `0.1` | Random jitter (10%) |
61
+
62
+ Has `reset!` method. All attributes are plain `attr_accessor`.
63
+
64
+ ---
65
+
66
+ ## HealthSettings
67
+
68
+ **File:** `lib/source_monitor/configuration/health_settings.rb`
69
+
70
+ | Attribute | Type | Default | Description |
71
+ |-----------|------|---------|-------------|
72
+ | `window_size` | Integer | `20` | Rolling window of fetches for health calc |
73
+ | `healthy_threshold` | Float | `0.8` | Success rate above = healthy |
74
+ | `warning_threshold` | Float | `0.5` | Success rate above = warning |
75
+ | `auto_pause_threshold` | Float | `0.2` | Success rate below = auto-pause |
76
+ | `auto_resume_threshold` | Float | `0.6` | Success rate above = auto-resume |
77
+ | `auto_pause_cooldown_minutes` | Integer | `60` | Cooldown before auto-resume check |
78
+
79
+ Has `reset!` method. All attributes are plain `attr_accessor`.
80
+
81
+ ---
82
+
83
+ ## ScrapingSettings
84
+
85
+ **File:** `lib/source_monitor/configuration/scraping_settings.rb`
86
+
87
+ | Attribute | Type | Default | Description |
88
+ |-----------|------|---------|-------------|
89
+ | `max_in_flight_per_source` | Integer/nil | `25` | Max concurrent scrape jobs per source |
90
+ | `max_bulk_batch_size` | Integer/nil | `100` | Max items in a bulk scrape batch |
91
+
92
+ Has `reset!` method. Custom setters normalize values:
93
+ - `nil` -> `nil`
94
+ - `""` -> `nil`
95
+ - `0` or negative -> `nil`
96
+ - String -> parsed integer (if positive)
97
+ - Positive integer -> kept as-is
98
+
99
+ ---
100
+
101
+ ## RetentionSettings
102
+
103
+ **File:** `lib/source_monitor/configuration/retention_settings.rb`
104
+
105
+ | Attribute | Type | Default | Description |
106
+ |-----------|------|---------|-------------|
107
+ | `items_retention_days` | Integer/nil | `nil` | Days to keep items (nil = forever) |
108
+ | `max_items` | Integer/nil | `nil` | Max items per source (nil = unlimited) |
109
+ | `strategy` | Symbol | `:destroy` | `:destroy` or `:soft_delete` |
110
+
111
+ No `reset!` method (defaults set in `initialize`). The `strategy=` setter validates against allowed values and raises `ArgumentError` for invalid input. Setting `nil` resets to `:destroy`.
112
+
113
+ ---
114
+
115
+ ## RealtimeSettings
116
+
117
+ **File:** `lib/source_monitor/configuration/realtime_settings.rb`
118
+
119
+ | Attribute | Type | Default | Description |
120
+ |-----------|------|---------|-------------|
121
+ | `adapter` | Symbol | `:solid_cable` | One of `:solid_cable`, `:redis`, `:async` |
122
+ | `redis_url` | String/nil | `nil` | Redis URL (for `:redis` adapter) |
123
+ | `solid_cable` | SolidCableOptions | (nested object) | Solid Cable options |
124
+
125
+ Has `reset!` method. The `adapter=` setter validates against `VALID_ADAPTERS`.
126
+
127
+ **SolidCableOptions:**
128
+
129
+ | Attribute | Type | Default |
130
+ |-----------|------|---------|
131
+ | `polling_interval` | String | `"0.1.seconds"` |
132
+ | `message_retention` | String | `"1.day"` |
133
+ | `autotrim` | Boolean | `true` |
134
+ | `silence_polling` | Boolean | `true` |
135
+ | `use_skip_locked` | Boolean | `true` |
136
+ | `trim_batch_size` | Integer/nil | `nil` |
137
+ | `connects_to` | Hash/nil | `nil` |
138
+
139
+ **Methods:**
140
+ - `action_cable_config` -- Returns hash suitable for ActionCable configuration
141
+ - `solid_cable=(hash)` -- Bulk-assign SolidCable options from a hash
142
+
143
+ ---
144
+
145
+ ## AuthenticationSettings
146
+
147
+ **File:** `lib/source_monitor/configuration/authentication_settings.rb`
148
+
149
+ | Attribute | Type | Default | Description |
150
+ |-----------|------|---------|-------------|
151
+ | `authenticate_handler` | Handler/nil | `nil` | Authentication handler |
152
+ | `authorize_handler` | Handler/nil | `nil` | Authorization handler |
153
+ | `current_user_method` | Symbol/nil | `nil` | Method name for current user |
154
+ | `user_signed_in_method` | Symbol/nil | `nil` | Method name for signed-in check |
155
+
156
+ Has `reset!` method.
157
+
158
+ **Methods:**
159
+ - `authenticate_with(handler = nil, &block)` -- Register authentication handler
160
+ - `authorize_with(handler = nil, &block)` -- Register authorization handler
161
+
162
+ Handler types: `:symbol` (method name), `:callable` (lambda/proc/block).
163
+
164
+ ---
165
+
166
+ ## Events
167
+
168
+ **File:** `lib/source_monitor/configuration/events.rb`
169
+
170
+ | Callback Key | Description |
171
+ |-------------|-------------|
172
+ | `after_item_created` | Fires after a new item is created from a feed entry |
173
+ | `after_item_scraped` | Fires after an item's content is scraped |
174
+ | `after_fetch_completed` | Fires after a feed fetch completes (success or failure) |
175
+
176
+ **Methods:**
177
+ - `after_item_created(handler = nil, &block)` -- Register callback
178
+ - `after_item_scraped(handler = nil, &block)` -- Register callback
179
+ - `after_fetch_completed(handler = nil, &block)` -- Register callback
180
+ - `register_item_processor(processor = nil, &block)` -- Register item processor
181
+ - `callbacks_for(name)` -- Returns array of callbacks (dup'd)
182
+ - `item_processors` -- Returns array of processors (dup'd)
183
+ - `reset!` -- Clears all callbacks and processors
184
+
185
+ All handlers must respond to `#call`. Raises `ArgumentError` otherwise.
186
+
187
+ ---
188
+
189
+ ## ScraperRegistry
190
+
191
+ **File:** `lib/source_monitor/configuration/scraper_registry.rb`
192
+
193
+ Enumerable registry of scraper adapters.
194
+
195
+ **Methods:**
196
+ - `register(name, adapter)` -- Register adapter class by name
197
+ - `unregister(name)` -- Remove adapter
198
+ - `adapter_for(name)` -- Look up adapter class by name
199
+ - `each` -- Iterate over `{name => adapter}` pairs
200
+
201
+ Names are normalized to lowercase alphanumeric + underscores. Adapter classes must inherit from `SourceMonitor::Scrapers::Base`.
202
+
203
+ ---
204
+
205
+ ## Models
206
+
207
+ **File:** `lib/source_monitor/configuration/models.rb`
208
+
209
+ | Attribute | Type | Default | Description |
210
+ |-----------|------|---------|-------------|
211
+ | `table_name_prefix` | String | `"sourcemon_"` | Database table prefix |
212
+
213
+ **Model Keys:** `source`, `item`, `fetch_log`, `scrape_log`, `health_check_log`, `item_content`, `log_entry`
214
+
215
+ Each key returns a `ModelDefinition` instance.
216
+
217
+ **Methods:**
218
+ - `for(name)` -- Returns `ModelDefinition` by name (raises on unknown)
219
+
220
+ ---
221
+
222
+ ## ModelDefinition
223
+
224
+ **File:** `lib/source_monitor/configuration/model_definition.rb`
225
+
226
+ **Methods:**
227
+ - `include_concern(concern = nil, &block)` -- Register a concern module
228
+ - `each_concern` -- Iterate over registered concerns (yields `[signature, resolved_module]`)
229
+ - `validate(handler = nil, **options, &block)` -- Register a custom validation
230
+ - `validations` -- Returns array of `ValidationDefinition` instances
231
+
232
+ Concerns can be: Module instance, String constant name, or anonymous block.
233
+ Validations can be: Symbol method name, String, lambda, or block.
234
+
235
+ ---
236
+
237
+ ## ValidationDefinition
238
+
239
+ **File:** `lib/source_monitor/configuration/validation_definition.rb`
240
+
241
+ | Attribute | Type | Description |
242
+ |-----------|------|-------------|
243
+ | `handler` | Symbol/Proc | The validation handler |
244
+ | `options` | Hash | Options hash (e.g., `{ if: :active? }`) |
245
+
246
+ **Methods:**
247
+ - `signature` -- Returns deduplication key
248
+ - `symbol?` -- Returns true if handler is a Symbol or String
@@ -0,0 +1,297 @@
1
+ # Step-by-Step: Adding a Configuration Setting
2
+
3
+ ## Scenario A: Add to Existing Section
4
+
5
+ ### Example: Add `stale_threshold_hours` to FetchingSettings
6
+
7
+ **Step 1: Edit the settings file**
8
+
9
+ ```ruby
10
+ # lib/source_monitor/configuration/fetching_settings.rb
11
+ class FetchingSettings
12
+ attr_accessor :min_interval_minutes,
13
+ :max_interval_minutes,
14
+ :increase_factor,
15
+ :decrease_factor,
16
+ :failure_increase_factor,
17
+ :jitter_percent,
18
+ :stale_threshold_hours # ADD: new accessor
19
+
20
+ def reset!
21
+ @min_interval_minutes = 5
22
+ @max_interval_minutes = 24 * 60
23
+ @increase_factor = 1.25
24
+ @decrease_factor = 0.75
25
+ @failure_increase_factor = 1.5
26
+ @jitter_percent = 0.1
27
+ @stale_threshold_hours = 48 # ADD: default value
28
+ end
29
+ end
30
+ ```
31
+
32
+ **Step 2: Write tests**
33
+
34
+ ```ruby
35
+ # test/lib/source_monitor/configuration_test.rb
36
+
37
+ test "stale_threshold_hours has correct default" do
38
+ assert_equal 48, SourceMonitor.config.fetching.stale_threshold_hours
39
+ end
40
+
41
+ test "stale_threshold_hours can be overridden" do
42
+ SourceMonitor.configure do |config|
43
+ config.fetching.stale_threshold_hours = 72
44
+ end
45
+ assert_equal 72, SourceMonitor.config.fetching.stale_threshold_hours
46
+ end
47
+
48
+ test "stale_threshold_hours resets with configuration" do
49
+ SourceMonitor.configure do |config|
50
+ config.fetching.stale_threshold_hours = 72
51
+ end
52
+ SourceMonitor.reset_configuration!
53
+ assert_equal 48, SourceMonitor.config.fetching.stale_threshold_hours
54
+ end
55
+ ```
56
+
57
+ **Step 3: Run tests**
58
+
59
+ ```bash
60
+ PARALLEL_WORKERS=1 bin/rails test test/lib/source_monitor/configuration_test.rb
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Scenario B: Add Setting with Validation
66
+
67
+ ### Example: Add validated `strategy` to a section
68
+
69
+ **Step 1: Edit the settings file with custom setter**
70
+
71
+ ```ruby
72
+ class MySettings
73
+ VALID_MODES = %i[fast balanced thorough].freeze
74
+
75
+ attr_reader :mode
76
+
77
+ def initialize
78
+ reset!
79
+ end
80
+
81
+ def mode=(value)
82
+ normalized = value&.to_sym
83
+ unless VALID_MODES.include?(normalized)
84
+ raise ArgumentError, "Invalid mode #{value.inspect}. Must be one of: #{VALID_MODES.join(', ')}"
85
+ end
86
+ @mode = normalized
87
+ end
88
+
89
+ def reset!
90
+ @mode = :balanced
91
+ end
92
+ end
93
+ ```
94
+
95
+ **Step 2: Write tests for all paths**
96
+
97
+ ```ruby
98
+ test "mode defaults to balanced" do
99
+ assert_equal :balanced, SourceMonitor.config.my_section.mode
100
+ end
101
+
102
+ test "mode accepts valid values" do
103
+ %i[fast balanced thorough].each do |mode|
104
+ SourceMonitor.configure do |config|
105
+ config.my_section.mode = mode
106
+ end
107
+ assert_equal mode, SourceMonitor.config.my_section.mode
108
+ end
109
+ end
110
+
111
+ test "mode accepts string values" do
112
+ SourceMonitor.configure do |config|
113
+ config.my_section.mode = "fast"
114
+ end
115
+ assert_equal :fast, SourceMonitor.config.my_section.mode
116
+ end
117
+
118
+ test "mode rejects invalid values" do
119
+ assert_raises(ArgumentError, /Invalid mode/) do
120
+ SourceMonitor.configure do |config|
121
+ config.my_section.mode = :invalid
122
+ end
123
+ end
124
+ end
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Scenario C: Add Setting with Normalization
130
+
131
+ ### Example: Numeric setting that normalizes edge cases
132
+
133
+ Follow the `ScrapingSettings` pattern:
134
+
135
+ ```ruby
136
+ class MySettings
137
+ DEFAULT_LIMIT = 50
138
+
139
+ attr_reader :limit
140
+
141
+ def initialize
142
+ reset!
143
+ end
144
+
145
+ def limit=(value)
146
+ @limit = normalize_numeric(value)
147
+ end
148
+
149
+ def reset!
150
+ @limit = DEFAULT_LIMIT
151
+ end
152
+
153
+ private
154
+
155
+ def normalize_numeric(value)
156
+ return nil if value.nil?
157
+ return nil if value == ""
158
+ integer = value.respond_to?(:to_i) ? value.to_i : value
159
+ integer.positive? ? integer : nil
160
+ end
161
+ end
162
+ ```
163
+
164
+ **Test normalization edge cases:**
165
+
166
+ ```ruby
167
+ test "limit normalizes string to integer" do
168
+ SourceMonitor.configure { |c| c.my_section.limit = "10" }
169
+ assert_equal 10, SourceMonitor.config.my_section.limit
170
+ end
171
+
172
+ test "limit normalizes nil to nil" do
173
+ SourceMonitor.configure { |c| c.my_section.limit = nil }
174
+ assert_nil SourceMonitor.config.my_section.limit
175
+ end
176
+
177
+ test "limit normalizes empty string to nil" do
178
+ SourceMonitor.configure { |c| c.my_section.limit = "" }
179
+ assert_nil SourceMonitor.config.my_section.limit
180
+ end
181
+
182
+ test "limit normalizes zero to nil" do
183
+ SourceMonitor.configure { |c| c.my_section.limit = 0 }
184
+ assert_nil SourceMonitor.config.my_section.limit
185
+ end
186
+
187
+ test "limit normalizes negative to nil" do
188
+ SourceMonitor.configure { |c| c.my_section.limit = -5 }
189
+ assert_nil SourceMonitor.config.my_section.limit
190
+ end
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Scenario D: Create a New Settings Section
196
+
197
+ ### Step 1: Create the settings file
198
+
199
+ ```ruby
200
+ # lib/source_monitor/configuration/notifications_settings.rb
201
+ # frozen_string_literal: true
202
+
203
+ module SourceMonitor
204
+ class Configuration
205
+ class NotificationsSettings
206
+ attr_accessor :enabled, :channels, :throttle_seconds
207
+
208
+ def initialize
209
+ reset!
210
+ end
211
+
212
+ def reset!
213
+ @enabled = true
214
+ @channels = []
215
+ @throttle_seconds = 60
216
+ end
217
+ end
218
+ end
219
+ end
220
+ ```
221
+
222
+ ### Step 2: Add require and reader to Configuration
223
+
224
+ ```ruby
225
+ # lib/source_monitor/configuration.rb
226
+
227
+ # At the top, add require:
228
+ require "source_monitor/configuration/notifications_settings"
229
+
230
+ # In the class:
231
+ attr_reader :http, :scrapers, :retention, :events, :models,
232
+ :realtime, :fetching, :health, :authentication, :scraping,
233
+ :notifications
234
+
235
+ # In initialize:
236
+ def initialize
237
+ # ... existing ...
238
+ @notifications = NotificationsSettings.new
239
+ end
240
+ ```
241
+
242
+ ### Step 3: Write tests
243
+
244
+ ```ruby
245
+ # test/lib/source_monitor/configuration_test.rb
246
+
247
+ test "notifications settings have correct defaults" do
248
+ settings = SourceMonitor.config.notifications
249
+ assert_equal true, settings.enabled
250
+ assert_equal [], settings.channels
251
+ assert_equal 60, settings.throttle_seconds
252
+ end
253
+
254
+ test "notifications settings can be configured" do
255
+ SourceMonitor.configure do |config|
256
+ config.notifications.enabled = false
257
+ config.notifications.channels = [:email]
258
+ config.notifications.throttle_seconds = 30
259
+ end
260
+
261
+ settings = SourceMonitor.config.notifications
262
+ assert_equal false, settings.enabled
263
+ assert_equal [:email], settings.channels
264
+ assert_equal 30, settings.throttle_seconds
265
+ end
266
+
267
+ test "notifications reset restores defaults" do
268
+ SourceMonitor.configure do |config|
269
+ config.notifications.enabled = false
270
+ end
271
+ SourceMonitor.reset_configuration!
272
+ assert_equal true, SourceMonitor.config.notifications.enabled
273
+ end
274
+ ```
275
+
276
+ ### Step 4: Run tests
277
+
278
+ ```bash
279
+ PARALLEL_WORKERS=1 bin/rails test test/lib/source_monitor/configuration_test.rb
280
+ ```
281
+
282
+ ---
283
+
284
+ ## Checklist for Any New Setting
285
+
286
+ - [ ] Attribute added to settings class (attr_accessor or custom setter)
287
+ - [ ] Default value set in `reset!` (or `initialize` for classes without `reset!`)
288
+ - [ ] require statement added (if new file)
289
+ - [ ] Reader method exposed on Configuration (if new section)
290
+ - [ ] Initialization in Configuration#initialize (if new section)
291
+ - [ ] Tests: default value is correct
292
+ - [ ] Tests: value can be overridden
293
+ - [ ] Tests: reset restores default
294
+ - [ ] Tests: validation raises ArgumentError (if applicable)
295
+ - [ ] Tests: edge cases for normalization (if applicable)
296
+ - [ ] All tests pass: `PARALLEL_WORKERS=1 bin/rails test test/lib/source_monitor/configuration_test.rb`
297
+ - [ ] RuboCop clean: `bin/rubocop lib/source_monitor/configuration/`
@@ -0,0 +1,153 @@
1
+ ---
2
+ name: sm-configure
3
+ description: Use when configuring SourceMonitor engine settings via the DSL, including queue settings, HTTP client, fetching, health, scrapers, retention, scraping controls, events, model extensions, realtime, and authentication.
4
+ allowed-tools: Read, Write, Edit, Bash, Glob, Grep
5
+ ---
6
+
7
+ # sm-configure: Engine Configuration DSL
8
+
9
+ Comprehensive reference for configuring SourceMonitor via `SourceMonitor.configure`.
10
+
11
+ ## When to Use
12
+
13
+ - Adding or modifying settings in `config/initializers/source_monitor.rb`
14
+ - Understanding what configuration options are available
15
+ - Debugging configuration-related issues
16
+ - Setting up environment-specific overrides
17
+
18
+ ## Configuration Entry Point
19
+
20
+ All configuration lives inside the `configure` block in the host app's initializer:
21
+
22
+ ```ruby
23
+ SourceMonitor.configure do |config|
24
+ # settings here
25
+ end
26
+ ```
27
+
28
+ After the block executes, `ModelExtensions.reload!` runs automatically to apply any model changes. Restart web and worker processes after changes.
29
+
30
+ ## Configuration Sections
31
+
32
+ The `config` object (`SourceMonitor::Configuration`) has 10 sub-sections plus top-level queue/job settings:
33
+
34
+ | Section | Accessor | Class |
35
+ |---|---|---|
36
+ | Top-level | `config.*` | `Configuration` |
37
+ | HTTP | `config.http` | `HTTPSettings` |
38
+ | Fetching | `config.fetching` | `FetchingSettings` |
39
+ | Health | `config.health` | `HealthSettings` |
40
+ | Scrapers | `config.scrapers` | `ScraperRegistry` |
41
+ | Retention | `config.retention` | `RetentionSettings` |
42
+ | Scraping | `config.scraping` | `ScrapingSettings` |
43
+ | Events | `config.events` | `Events` |
44
+ | Models | `config.models` | `Models` |
45
+ | Realtime | `config.realtime` | `RealtimeSettings` |
46
+ | Authentication | `config.authentication` | `AuthenticationSettings` |
47
+
48
+ See `reference/configuration-reference.md` for every setting with types, defaults, and examples.
49
+
50
+ ## Quick Examples
51
+
52
+ ### Queue Configuration
53
+ ```ruby
54
+ config.queue_namespace = "source_monitor"
55
+ config.fetch_queue_name = "source_monitor_fetch"
56
+ config.fetch_queue_concurrency = 4
57
+ ```
58
+
59
+ ### HTTP Client
60
+ ```ruby
61
+ config.http.timeout = 30
62
+ config.http.proxy = ENV["HTTP_PROXY"]
63
+ config.http.retry_max = 3
64
+ ```
65
+
66
+ ### Authentication (Devise)
67
+ ```ruby
68
+ config.authentication.authenticate_with :authenticate_user!
69
+ config.authentication.authorize_with ->(c) { c.current_user&.admin? }
70
+ ```
71
+
72
+ ### Events
73
+ ```ruby
74
+ config.events.after_item_created { |e| Notifier.new_item(e.item) }
75
+ config.events.register_item_processor ->(ctx) { Indexer.index(ctx.item) }
76
+ ```
77
+
78
+ ### Model Extensions
79
+ ```ruby
80
+ config.models.table_name_prefix = "sm_"
81
+ config.models.source.include_concern "MyApp::SourceExtension"
82
+ config.models.item.validate :custom_check
83
+ ```
84
+
85
+ ### Realtime
86
+ ```ruby
87
+ config.realtime.adapter = :redis
88
+ config.realtime.redis_url = ENV["REDIS_URL"]
89
+ ```
90
+
91
+ ## Helper APIs
92
+
93
+ ```ruby
94
+ SourceMonitor.config # Current configuration
95
+ SourceMonitor.configure { |c| ... } # Set configuration
96
+ SourceMonitor.reset_configuration! # Revert to defaults (for tests)
97
+ SourceMonitor.events # Shortcut to config.events
98
+ SourceMonitor.queue_name(:fetch) # Resolved queue name
99
+ SourceMonitor.queue_concurrency(:scrape) # Resolved concurrency
100
+ SourceMonitor.mission_control_dashboard_path # Resolved MC path or nil
101
+ ```
102
+
103
+ ## Key Source Files
104
+
105
+ | File | Purpose |
106
+ |---|---|
107
+ | `lib/source_monitor/configuration.rb` | Main Configuration class |
108
+ | `lib/source_monitor/configuration/http_settings.rb` | HTTP client settings |
109
+ | `lib/source_monitor/configuration/fetching_settings.rb` | Adaptive scheduling |
110
+ | `lib/source_monitor/configuration/health_settings.rb` | Health monitoring |
111
+ | `lib/source_monitor/configuration/scraper_registry.rb` | Scraper adapter registry |
112
+ | `lib/source_monitor/configuration/retention_settings.rb` | Item retention |
113
+ | `lib/source_monitor/configuration/scraping_settings.rb` | Scraping controls |
114
+ | `lib/source_monitor/configuration/events.rb` | Event callbacks |
115
+ | `lib/source_monitor/configuration/models.rb` | Model extensions config |
116
+ | `lib/source_monitor/configuration/model_definition.rb` | Per-model definition |
117
+ | `lib/source_monitor/configuration/realtime_settings.rb` | Action Cable settings |
118
+ | `lib/source_monitor/configuration/authentication_settings.rb` | Auth settings |
119
+ | `lib/source_monitor/configuration/validation_definition.rb` | Validation wrapper |
120
+
121
+ ## References
122
+
123
+ - `reference/configuration-reference.md` -- Complete settings reference
124
+ - `docs/configuration.md` -- Official configuration documentation
125
+ - `lib/generators/source_monitor/install/templates/source_monitor.rb.tt` -- Initializer template
126
+
127
+ ## Testing
128
+
129
+ Reset configuration between tests:
130
+ ```ruby
131
+ setup do
132
+ SourceMonitor.reset_configuration!
133
+ end
134
+ ```
135
+
136
+ Test custom configuration:
137
+ ```ruby
138
+ test "custom queue name" do
139
+ SourceMonitor.configure do |config|
140
+ config.fetch_queue_name = "custom_fetch"
141
+ end
142
+ assert_equal "custom_fetch", SourceMonitor.queue_name(:fetch)
143
+ end
144
+ ```
145
+
146
+ ## Checklist
147
+
148
+ - [ ] Initializer exists at `config/initializers/source_monitor.rb`
149
+ - [ ] Queue names match `config/solid_queue.yml` entries
150
+ - [ ] Authentication hooks configured for host auth system
151
+ - [ ] HTTP timeouts appropriate for target feeds
152
+ - [ ] Retention policy set for production
153
+ - [ ] Workers restarted after configuration changes