source_monitor 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/skills/sm-configure/SKILL.md +10 -1
- data/.claude/skills/sm-configure/reference/configuration-reference.md +44 -0
- data/.claude/skills/sm-host-setup/reference/initializer-template.md +17 -0
- data/.claude/skills/sm-host-setup/reference/setup-checklist.md +2 -0
- data/.claude/skills/sm-job/reference/job-conventions.md +26 -0
- data/.claude/skills/sm-upgrade/reference/version-history.md +22 -0
- data/.gitignore +10 -0
- data/AGENTS.md +1 -1
- data/CHANGELOG.md +35 -0
- data/CLAUDE.md +11 -5
- data/Gemfile.lock +1 -1
- data/README.md +6 -4
- data/VERSION +1 -1
- data/app/assets/builds/source_monitor/application.css +43 -0
- data/app/assets/builds/source_monitor/application.js +127 -0
- data/app/assets/builds/source_monitor/application.js.map +3 -3
- data/app/assets/javascripts/source_monitor/application.js +2 -0
- data/app/assets/javascripts/source_monitor/controllers/notification_container_controller.js +138 -0
- data/app/assets/javascripts/source_monitor/controllers/notification_controller.js +11 -0
- data/app/controllers/source_monitor/source_favicon_fetches_controller.rb +38 -0
- data/app/controllers/source_monitor/sources_controller.rb +11 -0
- data/app/helpers/source_monitor/application_helper.rb +51 -0
- data/app/jobs/source_monitor/favicon_fetch_job.rb +71 -0
- data/app/jobs/source_monitor/import_opml_job.rb +9 -0
- data/app/jobs/source_monitor/source_health_check_job.rb +10 -0
- data/app/models/source_monitor/source.rb +2 -0
- data/app/views/layouts/source_monitor/application.html.erb +23 -2
- data/app/views/source_monitor/shared/_toast.html.erb +1 -0
- data/app/views/source_monitor/sources/_details.html.erb +34 -5
- data/app/views/source_monitor/sources/_row.html.erb +11 -6
- data/config/routes.rb +1 -0
- data/docs/configuration.md +1 -1
- data/docs/upgrade.md +22 -0
- data/lib/generators/source_monitor/install/templates/source_monitor.rb.tt +15 -1
- data/lib/source_monitor/configuration/favicons_settings.rb +42 -0
- data/lib/source_monitor/configuration/http_settings.rb +1 -1
- data/lib/source_monitor/configuration/scraping_settings.rb +1 -1
- data/lib/source_monitor/configuration.rb +3 -1
- data/lib/source_monitor/favicons/discoverer.rb +196 -0
- data/lib/source_monitor/fetching/feed_fetcher/source_updater.rb +21 -0
- data/lib/source_monitor/fetching/feed_fetcher.rb +1 -0
- data/lib/source_monitor/http.rb +5 -3
- data/lib/source_monitor/version.rb +1 -1
- data/lib/source_monitor.rb +4 -0
- data/source_monitor.gemspec +1 -1
- metadata +6 -106
- data/.vbw-planning/PROJECT.md +0 -51
- data/.vbw-planning/ROADMAP.md +0 -53
- data/.vbw-planning/SHIPPED.md +0 -63
- data/.vbw-planning/STATE.md +0 -27
- data/.vbw-planning/codebase/ARCHITECTURE.md +0 -147
- data/.vbw-planning/codebase/CONCERNS.md +0 -99
- data/.vbw-planning/codebase/CONVENTIONS.md +0 -97
- data/.vbw-planning/codebase/DEPENDENCIES.md +0 -100
- data/.vbw-planning/codebase/INDEX.md +0 -86
- data/.vbw-planning/codebase/META.md +0 -42
- data/.vbw-planning/codebase/PATTERNS.md +0 -262
- data/.vbw-planning/codebase/STACK.md +0 -101
- data/.vbw-planning/codebase/STRUCTURE.md +0 -324
- data/.vbw-planning/codebase/TESTING.md +0 -154
- data/.vbw-planning/config.json +0 -53
- data/.vbw-planning/discovery.json +0 -26
- data/.vbw-planning/milestones/default/ROADMAP.md +0 -115
- data/.vbw-planning/milestones/default/STATE.md +0 -82
- data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-01-SUMMARY.md +0 -56
- data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-01.md +0 -187
- data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-02-SUMMARY.md +0 -64
- data/.vbw-planning/milestones/default/phases/01-coverage-analysis-quick-wins/PLAN-02.md +0 -137
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-01-SUMMARY.md +0 -67
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-01.md +0 -142
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-02-SUMMARY.md +0 -64
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-02.md +0 -138
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-03-SUMMARY.md +0 -85
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-03.md +0 -147
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-04-SUMMARY.md +0 -63
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-04.md +0 -129
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-05-SUMMARY.md +0 -74
- data/.vbw-planning/milestones/default/phases/02-critical-path-test-coverage/PLAN-05.md +0 -154
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/03-VERIFICATION-wave1.md +0 -303
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/03-VERIFICATION.md +0 -510
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-01-SUMMARY.md +0 -61
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-01.md +0 -161
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-02-SUMMARY.md +0 -66
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-02.md +0 -132
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-03-SUMMARY.md +0 -59
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-03.md +0 -171
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-04-SUMMARY.md +0 -56
- data/.vbw-planning/milestones/default/phases/03-large-file-refactoring/PLAN-04.md +0 -152
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/04-CONTEXT.md +0 -33
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-01-SUMMARY.md +0 -42
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-01.md +0 -119
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-02-SUMMARY.md +0 -52
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-02.md +0 -195
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-03-SUMMARY.md +0 -79
- data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-03.md +0 -130
- data/.vbw-planning/milestones/generator-enhancements/REQUIREMENTS.md +0 -72
- data/.vbw-planning/milestones/generator-enhancements/ROADMAP.md +0 -125
- data/.vbw-planning/milestones/generator-enhancements/SHIPPED.md +0 -40
- data/.vbw-planning/milestones/generator-enhancements/STATE.md +0 -43
- data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/01-CONTEXT.md +0 -33
- data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/01-VERIFICATION.md +0 -86
- data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/PLAN-01-SUMMARY.md +0 -61
- data/.vbw-planning/milestones/generator-enhancements/phases/01-generator-steps/PLAN-01.md +0 -380
- data/.vbw-planning/milestones/generator-enhancements/phases/02-verification/02-VERIFICATION.md +0 -78
- data/.vbw-planning/milestones/generator-enhancements/phases/02-verification/PLAN-01-SUMMARY.md +0 -46
- data/.vbw-planning/milestones/generator-enhancements/phases/02-verification/PLAN-01.md +0 -500
- data/.vbw-planning/milestones/generator-enhancements/phases/03-docs-alignment/03-VERIFICATION.md +0 -89
- data/.vbw-planning/milestones/generator-enhancements/phases/03-docs-alignment/PLAN-01-SUMMARY.md +0 -48
- data/.vbw-planning/milestones/generator-enhancements/phases/03-docs-alignment/PLAN-01.md +0 -456
- data/.vbw-planning/milestones/generator-enhancements/phases/04-dashboard-ux/04-VERIFICATION.md +0 -129
- data/.vbw-planning/milestones/generator-enhancements/phases/04-dashboard-ux/PLAN-01-SUMMARY.md +0 -70
- data/.vbw-planning/milestones/generator-enhancements/phases/04-dashboard-ux/PLAN-01.md +0 -747
- data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/05-VERIFICATION.md +0 -156
- data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-01-SUMMARY.md +0 -69
- data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-01.md +0 -455
- data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-02-SUMMARY.md +0 -39
- data/.vbw-planning/milestones/generator-enhancements/phases/05-active-storage-images/PLAN-02.md +0 -488
- data/.vbw-planning/milestones/generator-enhancements/phases/06-netflix-feed-fix/06-VERIFICATION.md +0 -100
- data/.vbw-planning/milestones/generator-enhancements/phases/06-netflix-feed-fix/PLAN-01-SUMMARY.md +0 -37
- data/.vbw-planning/milestones/generator-enhancements/phases/06-netflix-feed-fix/PLAN-01.md +0 -345
- data/.vbw-planning/milestones/upgrade-assurance/REQUIREMENTS.md +0 -80
- data/.vbw-planning/milestones/upgrade-assurance/ROADMAP.md +0 -75
- data/.vbw-planning/milestones/upgrade-assurance/STATE.md +0 -29
- data/.vbw-planning/milestones/upgrade-assurance/phases/01-upgrade-command/01-VERIFICATION.md +0 -144
- data/.vbw-planning/milestones/upgrade-assurance/phases/01-upgrade-command/PLAN-01-SUMMARY.md +0 -43
- data/.vbw-planning/milestones/upgrade-assurance/phases/01-upgrade-command/PLAN-01.md +0 -405
- data/.vbw-planning/milestones/upgrade-assurance/phases/02-config-deprecation/PLAN-01-SUMMARY.md +0 -27
- data/.vbw-planning/milestones/upgrade-assurance/phases/02-config-deprecation/PLAN-01.md +0 -303
- data/.vbw-planning/milestones/upgrade-assurance/phases/03-upgrade-skill-docs/03-VERIFICATION.md +0 -380
- data/.vbw-planning/milestones/upgrade-assurance/phases/03-upgrade-skill-docs/PLAN-01-SUMMARY.md +0 -36
- data/.vbw-planning/milestones/upgrade-assurance/phases/03-upgrade-skill-docs/PLAN-01.md +0 -652
- data/.vbw-planning/phases/01-aia-certificate-resolution/.context-dev.md +0 -17
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-01-SUMMARY.md +0 -26
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-01.md +0 -71
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-02-SUMMARY.md +0 -16
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-02.md +0 -56
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-03-SUMMARY.md +0 -17
- data/.vbw-planning/phases/01-aia-certificate-resolution/PLAN-03.md +0 -98
- data/.vbw-planning/phases/02-test-performance/.context-dev.md +0 -75
- data/.vbw-planning/phases/02-test-performance/.context-lead.md +0 -89
- data/.vbw-planning/phases/02-test-performance/.context-qa.md +0 -23
- data/.vbw-planning/phases/02-test-performance/02-RESEARCH.md +0 -56
- data/.vbw-planning/phases/02-test-performance/02-VERIFICATION.md +0 -51
- data/.vbw-planning/phases/02-test-performance/PLAN-01-SUMMARY.md +0 -37
- data/.vbw-planning/phases/02-test-performance/PLAN-01.md +0 -156
- data/.vbw-planning/phases/02-test-performance/PLAN-02-SUMMARY.md +0 -33
- data/.vbw-planning/phases/02-test-performance/PLAN-02.md +0 -120
- data/.vbw-planning/phases/02-test-performance/PLAN-03-SUMMARY.md +0 -30
- data/.vbw-planning/phases/02-test-performance/PLAN-03.md +0 -154
- data/.vbw-planning/phases/02-test-performance/PLAN-04-SUMMARY.md +0 -28
- data/.vbw-planning/phases/02-test-performance/PLAN-04.md +0 -133
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
phase: 4
|
|
3
|
-
plan: 2
|
|
4
|
-
title: item-creator-extraction
|
|
5
|
-
wave: 1
|
|
6
|
-
depends_on: []
|
|
7
|
-
skills_used: []
|
|
8
|
-
cross_phase_deps:
|
|
9
|
-
- "Phase 3 Plan 01 -- FeedFetcher extraction pattern (sub-module directory with require from main file)"
|
|
10
|
-
- "Phase 2 Plan 02 -- ItemCreator tests exist at test/lib/source_monitor/items/item_creator_test.rb"
|
|
11
|
-
must_haves:
|
|
12
|
-
truths:
|
|
13
|
-
- "Running `wc -l lib/source_monitor/items/item_creator.rb` shows fewer than 300 lines"
|
|
14
|
-
- "Running `bin/rails test test/lib/source_monitor/items/item_creator_test.rb` exits 0 with zero failures"
|
|
15
|
-
- "Running `bin/rails test` exits 0 with 760+ runs and 0 failures"
|
|
16
|
-
- "Running `ruby -c lib/source_monitor/items/item_creator.rb` exits 0 (valid syntax)"
|
|
17
|
-
- "Running `ruby -c lib/source_monitor/items/item_creator/content_extractor.rb` exits 0"
|
|
18
|
-
- "Running `ruby -c lib/source_monitor/items/item_creator/entry_parser.rb` exits 0"
|
|
19
|
-
- "Running `bin/rubocop lib/source_monitor/items/item_creator.rb lib/source_monitor/items/item_creator/` exits 0"
|
|
20
|
-
artifacts:
|
|
21
|
-
- "lib/source_monitor/items/item_creator/entry_parser.rb -- extracted entry field parsing (guid, url, authors, enclosures, media, metadata, etc.)"
|
|
22
|
-
- "lib/source_monitor/items/item_creator/content_extractor.rb -- extracted feed content processing and readability"
|
|
23
|
-
- "lib/source_monitor/items/item_creator.rb -- slimmed to orchestrator under 300 lines"
|
|
24
|
-
key_links:
|
|
25
|
-
- "Phase 4 success criterion #1 -- all service objects follow established conventions"
|
|
26
|
-
- "No single file exceeds 300 lines (extends Phase 3 criterion)"
|
|
27
|
-
- "Public API unchanged -- ItemCreator.call(source:, entry:) returns Result struct"
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
# Plan 02: item-creator-extraction
|
|
31
|
-
|
|
32
|
-
## Objective
|
|
33
|
-
|
|
34
|
-
Extract `lib/source_monitor/items/item_creator.rb` (601 lines, 50+ methods) into focused sub-modules following the exact same extraction pattern used by `FeedFetcher` in Phase 3 (sub-module directory with require from main file). The public API (`ItemCreator.call(source:, entry:)` returning a `Result` struct) must remain unchanged. All existing ItemCreator tests must continue to pass without modification.
|
|
35
|
-
|
|
36
|
-
## Context
|
|
37
|
-
|
|
38
|
-
<context>
|
|
39
|
-
@lib/source_monitor/items/item_creator.rb -- 601 lines with 50+ methods. The largest file in the codebase after Phase 3 refactoring. Contains three clearly separable responsibility clusters:
|
|
40
|
-
|
|
41
|
-
**Cluster 1: Core attribute building (build_attributes, ~90 lines)**
|
|
42
|
-
The `build_attributes` method (lines 233-271) assembles all item attributes by calling field extraction methods. This is the main orchestration method and should stay in the main file.
|
|
43
|
-
|
|
44
|
-
**Cluster 2: Field extraction from feed entries (~300 lines)**
|
|
45
|
-
Methods that extract specific fields from Feedjira entry objects:
|
|
46
|
-
- `extract_guid` (lines 273-287)
|
|
47
|
-
- `extract_url` (lines 288-311)
|
|
48
|
-
- `extract_summary` (lines 312-317)
|
|
49
|
-
- `extract_content` (lines 318-327)
|
|
50
|
-
- `extract_timestamp` (lines 328-337)
|
|
51
|
-
- `extract_updated_timestamp` (lines 338-343)
|
|
52
|
-
- `extract_author` (lines 344-347)
|
|
53
|
-
- `extract_authors` (lines 348-384)
|
|
54
|
-
- `extract_categories` (lines 385-394)
|
|
55
|
-
- `extract_tags` (lines 395-408)
|
|
56
|
-
- `extract_keywords` (lines 409-415)
|
|
57
|
-
- `extract_enclosures` (lines 416-467)
|
|
58
|
-
- `extract_media_thumbnail_url` (lines 468-476)
|
|
59
|
-
- `extract_media_content` (lines 477-500)
|
|
60
|
-
- `extract_language` (lines 501-512)
|
|
61
|
-
- `extract_copyright` (lines 513-524)
|
|
62
|
-
- `extract_comments_url` (lines 525-528)
|
|
63
|
-
- `extract_comments_count` (lines 529-535)
|
|
64
|
-
- `extract_metadata` (lines 536-544)
|
|
65
|
-
Plus utility methods: `generate_fingerprint`, `string_or_nil`, `sanitize_string_array`, `split_keywords`, `safe_integer`, `json_entry?`, `atom_entry?`, `normalize_metadata` (lines 545-601)
|
|
66
|
-
|
|
67
|
-
**Cluster 3: Feed content processing (~75 lines)**
|
|
68
|
-
Methods for processing raw feed content through readability:
|
|
69
|
-
- `process_feed_content` (lines 137-158)
|
|
70
|
-
- `should_process_feed_content?` (lines 160-165)
|
|
71
|
-
- `feed_content_parser_class` (lines 167-170)
|
|
72
|
-
- `wrap_content_for_readability` (lines 171-186)
|
|
73
|
-
- `default_feed_readability_options` (lines 187-193)
|
|
74
|
-
- `build_feed_content_metadata` (lines 194-209)
|
|
75
|
-
- `html_fragment?` (lines 210-213)
|
|
76
|
-
- `deep_copy` (lines 214-231)
|
|
77
|
-
|
|
78
|
-
**What stays in the main file (~200 lines):**
|
|
79
|
-
- Result struct definition
|
|
80
|
-
- Constants (FINGERPRINT_SEPARATOR, CONTENT_METHODS, etc.)
|
|
81
|
-
- Constructor, `self.call`, `call` method
|
|
82
|
-
- `existing_item_for`, `find_item_by_guid`, `find_item_by_fingerprint`
|
|
83
|
-
- `instrument_duplicate`, `update_existing_item`, `create_new_item`
|
|
84
|
-
- `handle_concurrent_duplicate`, `find_conflicting_item`, `apply_attributes`
|
|
85
|
-
- `build_attributes` (calls into extracted modules)
|
|
86
|
-
- Lazy accessor methods for sub-modules
|
|
87
|
-
|
|
88
|
-
@lib/source_monitor/fetching/feed_fetcher.rb -- 285 lines. The extraction pattern to follow: main file requires sub-modules, uses lazy accessors (e.g., `def source_updater; @source_updater ||= SourceUpdater.new(...); end`), delegates method calls.
|
|
89
|
-
@lib/source_monitor/fetching/feed_fetcher/source_updater.rb -- Example sub-module: namespaced under FeedFetcher, constructor receives dependencies.
|
|
90
|
-
@lib/source_monitor/fetching/feed_fetcher/entry_processor.rb -- Another example sub-module.
|
|
91
|
-
@test/lib/source_monitor/items/item_creator_test.rb -- Existing tests. Must pass without modification.
|
|
92
|
-
</context>
|
|
93
|
-
|
|
94
|
-
## Tasks
|
|
95
|
-
|
|
96
|
-
### Task 1: Extract EntryParser module
|
|
97
|
-
|
|
98
|
-
- **name:** extract-entry-parser
|
|
99
|
-
- **files:**
|
|
100
|
-
- `lib/source_monitor/items/item_creator/entry_parser.rb` (new)
|
|
101
|
-
- `lib/source_monitor/items/item_creator.rb`
|
|
102
|
-
- **action:** Create `lib/source_monitor/items/item_creator/entry_parser.rb` containing a `SourceMonitor::Items::ItemCreator::EntryParser` class. Move these methods from item_creator.rb into the new class:
|
|
103
|
-
- `extract_guid` -- entry GUID extraction with JSON/Atom fallbacks
|
|
104
|
-
- `extract_url` -- URL extraction with canonical/alternate link resolution
|
|
105
|
-
- `extract_summary` -- summary text extraction
|
|
106
|
-
- `extract_content` -- content extraction from multiple methods
|
|
107
|
-
- `extract_timestamp` -- published_at extraction
|
|
108
|
-
- `extract_updated_timestamp` -- updated_at extraction
|
|
109
|
-
- `extract_author` -- single author extraction
|
|
110
|
-
- `extract_authors` -- multi-author extraction with JSON parsing
|
|
111
|
-
- `extract_categories` -- category extraction
|
|
112
|
-
- `extract_tags` -- tag extraction
|
|
113
|
-
- `extract_keywords` -- keyword extraction with separator splitting
|
|
114
|
-
- `extract_enclosures` -- enclosure/attachment extraction
|
|
115
|
-
- `extract_media_thumbnail_url` -- media thumbnail extraction
|
|
116
|
-
- `extract_media_content` -- media content metadata extraction
|
|
117
|
-
- `extract_language` -- language detection
|
|
118
|
-
- `extract_copyright` -- copyright extraction
|
|
119
|
-
- `extract_comments_url` -- comments link extraction
|
|
120
|
-
- `extract_comments_count` -- comments count extraction
|
|
121
|
-
- `extract_metadata` -- raw metadata extraction
|
|
122
|
-
- `generate_fingerprint` -- content fingerprint generation
|
|
123
|
-
- Utility methods: `string_or_nil`, `sanitize_string_array`, `split_keywords`, `safe_integer`, `json_entry?`, `atom_entry?`, `normalize_metadata`
|
|
124
|
-
|
|
125
|
-
The EntryParser constructor takes `source:` and `entry:` (same as ItemCreator). It exposes a single public method `parse` that returns a hash of all extracted attributes (what `build_attributes` currently assembles). Add `require_relative "item_creator/entry_parser"` at the top of item_creator.rb. In ItemCreator, create an `entry_parser` lazy accessor and delegate the field extraction to it.
|
|
126
|
-
- **verify:** `ruby -c lib/source_monitor/items/item_creator/entry_parser.rb` exits 0 AND `bin/rails test test/lib/source_monitor/items/item_creator_test.rb` exits 0 with zero failures
|
|
127
|
-
- **done:** EntryParser extracted with all field extraction methods. Tests pass unchanged.
|
|
128
|
-
|
|
129
|
-
### Task 2: Extract ContentExtractor module
|
|
130
|
-
|
|
131
|
-
- **name:** extract-content-extractor
|
|
132
|
-
- **files:**
|
|
133
|
-
- `lib/source_monitor/items/item_creator/content_extractor.rb` (new)
|
|
134
|
-
- `lib/source_monitor/items/item_creator.rb`
|
|
135
|
-
- **action:** Create `lib/source_monitor/items/item_creator/content_extractor.rb` containing a `SourceMonitor::Items::ItemCreator::ContentExtractor` class. Move these methods:
|
|
136
|
-
- `process_feed_content` -- orchestrates content processing through readability
|
|
137
|
-
- `should_process_feed_content?` -- determines if content should be processed
|
|
138
|
-
- `feed_content_parser_class` -- resolves the parser class
|
|
139
|
-
- `wrap_content_for_readability` -- wraps raw content with HTML structure for parsing
|
|
140
|
-
- `default_feed_readability_options` -- default options for readability
|
|
141
|
-
- `build_feed_content_metadata` -- builds metadata about processing results
|
|
142
|
-
- `html_fragment?` -- checks if content is HTML
|
|
143
|
-
- `deep_copy` -- deep copies complex values
|
|
144
|
-
|
|
145
|
-
The ContentExtractor constructor takes `source:`. It exposes `process_feed_content(raw_content, title:)` as the primary public method. Add `require_relative "item_creator/content_extractor"` at the top of item_creator.rb. In ItemCreator, create a `content_extractor` lazy accessor. The EntryParser from Task 1 should call `content_extractor.process_feed_content(...)` instead of the local method -- wire this through the constructor or pass as a dependency.
|
|
146
|
-
- **verify:** `ruby -c lib/source_monitor/items/item_creator/content_extractor.rb` exits 0 AND `bin/rails test test/lib/source_monitor/items/item_creator_test.rb` exits 0
|
|
147
|
-
- **done:** ContentExtractor extracted. Feed content processing isolated. Tests pass unchanged.
|
|
148
|
-
|
|
149
|
-
### Task 3: Slim main ItemCreator and wire modules
|
|
150
|
-
|
|
151
|
-
- **name:** slim-item-creator-and-wire
|
|
152
|
-
- **files:**
|
|
153
|
-
- `lib/source_monitor/items/item_creator.rb`
|
|
154
|
-
- **action:** After Tasks 1-2, the main item_creator.rb should contain:
|
|
155
|
-
- Require statements for 2 sub-modules
|
|
156
|
-
- Existing requires (digest, json, cgi, etc.)
|
|
157
|
-
- Result struct definition
|
|
158
|
-
- Constants (FINGERPRINT_SEPARATOR, CONTENT_METHODS, TIMESTAMP_METHODS, etc.)
|
|
159
|
-
- Constructor and `self.call`
|
|
160
|
-
- `call` method (find or create)
|
|
161
|
-
- `existing_item_for`, `find_item_by_guid`, `find_item_by_fingerprint`
|
|
162
|
-
- `instrument_duplicate`, `update_existing_item`, `create_new_item`
|
|
163
|
-
- `handle_concurrent_duplicate`, `find_conflicting_item`, `apply_attributes`
|
|
164
|
-
- `build_attributes` (now delegates to entry_parser.parse)
|
|
165
|
-
- Lazy accessor methods for entry_parser and content_extractor
|
|
166
|
-
|
|
167
|
-
Clean up any dead code, orphaned requires, or duplicated constants. Ensure the main file is under 300 lines. Run RuboCop on all modified/new files.
|
|
168
|
-
- **verify:** `wc -l lib/source_monitor/items/item_creator.rb` shows fewer than 300 lines AND `bin/rubocop lib/source_monitor/items/item_creator.rb lib/source_monitor/items/item_creator/` exits 0 AND `bin/rails test test/lib/source_monitor/items/item_creator_test.rb` exits 0
|
|
169
|
-
- **done:** ItemCreator main file under 300 lines. All sub-modules wired. RuboCop clean.
|
|
170
|
-
|
|
171
|
-
### Task 4: Full test suite regression check
|
|
172
|
-
|
|
173
|
-
- **name:** full-regression-check
|
|
174
|
-
- **files:** (no new modifications -- verification only)
|
|
175
|
-
- **action:** Run the complete test suite to verify no regressions from the extraction. Check that: (a) all 760+ tests pass, (b) no new RuboCop violations, (c) ItemCreator public API (`ItemCreator.call(source:, entry:)` returning `Result` struct) works identically to before the extraction. Verify by inspecting any tests that use ItemCreator in other test files (e.g., feed_fetcher_test.rb, import_opml_job tests) to confirm they still pass.
|
|
176
|
-
- **verify:** `bin/rails test` exits 0 with 760+ runs and 0 failures AND `bin/rubocop -f simple` shows `no offenses detected`
|
|
177
|
-
- **done:** Full suite passes. Zero RuboCop violations. No regressions from extraction.
|
|
178
|
-
|
|
179
|
-
## Verification
|
|
180
|
-
|
|
181
|
-
1. `wc -l lib/source_monitor/items/item_creator.rb` shows fewer than 300 lines
|
|
182
|
-
2. `wc -l lib/source_monitor/items/item_creator/entry_parser.rb lib/source_monitor/items/item_creator/content_extractor.rb` shows both exist
|
|
183
|
-
3. `bin/rails test test/lib/source_monitor/items/item_creator_test.rb` exits 0 with zero failures
|
|
184
|
-
4. `bin/rails test` exits 0 with 760+ runs and 0 failures
|
|
185
|
-
5. `bin/rubocop lib/source_monitor/items/` exits 0
|
|
186
|
-
|
|
187
|
-
## Success Criteria
|
|
188
|
-
|
|
189
|
-
- [ ] ItemCreator main file under 300 lines
|
|
190
|
-
- [ ] Two sub-modules created: entry_parser.rb, content_extractor.rb
|
|
191
|
-
- [ ] Public API unchanged -- ItemCreator.call(source:, entry:) returns Result struct
|
|
192
|
-
- [ ] All existing tests pass without modification
|
|
193
|
-
- [ ] Full test suite passes (760+ runs, 0 failures)
|
|
194
|
-
- [ ] RuboCop passes on all modified/new files
|
|
195
|
-
- [ ] No file in app/ or lib/ exceeds 300 lines (extends Phase 3 success criterion)
|
data/.vbw-planning/milestones/default/phases/04-code-quality-conventions-cleanup/PLAN-03-SUMMARY.md
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
phase: 4
|
|
3
|
-
plan: 3
|
|
4
|
-
title: final-verification
|
|
5
|
-
status: complete
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Plan 03 Summary: final-verification
|
|
9
|
-
|
|
10
|
-
## What Was Done
|
|
11
|
-
|
|
12
|
-
1. **Regenerated coverage baseline** -- Coverage baseline reduced from 2117 to 510 uncovered lines (75.9% reduction, far exceeding the 60% target of 847).
|
|
13
|
-
|
|
14
|
-
2. **Fixed test isolation** -- Scoped test queries to specific source/item to prevent cross-test contamination from parallel test state leakage. Affected files: log_cleanup_job_test.rb, paginator_test.rb, item_test.rb, scrape_log_test.rb.
|
|
15
|
-
|
|
16
|
-
3. **Fixed coverage test infrastructure** -- Updated test_helper.rb to use threads with 1 worker for coverage runs (prevents SimpleCov data loss). Removed `refuse_coverage_drop :line` that was blocking coverage regeneration.
|
|
17
|
-
|
|
18
|
-
4. **Fixed remaining RuboCop violations** -- Autocorrected 22 `Layout/SpaceInsideArrayLiteralBrackets` offenses in Phase 2 configuration test files plus 1 `Layout/TrailingEmptyLines` in a generated temp file.
|
|
19
|
-
|
|
20
|
-
5. **Extracted modules to bring all files under 300 lines:**
|
|
21
|
-
- EntryParser (308->294): MediaExtraction module extracted
|
|
22
|
-
- Queries (356->163): StatsQuery and RecentActivityQuery extracted
|
|
23
|
-
- ApplicationHelper (346->236): TableSortHelper and HealthBadgeHelper extracted
|
|
24
|
-
- Added test/lib/tmp/ to .rubocop.yml exclusions
|
|
25
|
-
|
|
26
|
-
6. **CI-equivalent verification passed:**
|
|
27
|
-
- `bin/rubocop -f simple`: 372 files inspected, no offenses detected
|
|
28
|
-
- `bin/brakeman --no-pager -q`: 0 warnings
|
|
29
|
-
- `bin/rails test`: 841 runs, 2776 assertions, 0 failures, 0 errors
|
|
30
|
-
- No file in app/ or lib/ exceeds 300 lines (max: 294)
|
|
31
|
-
- All models and controllers have frozen_string_literal: true
|
|
32
|
-
|
|
33
|
-
7. **Conventions spot-check** -- All core models use ModelExtensions.register (ImportHistory/ImportSession intentionally excluded -- not in MODEL_KEYS). Concerns use ActiveSupport::Concern, jobs inherit from ApplicationJob, no commented-out code. One documented TODO in items_controller.rb. Struct keyword_init not needed (Ruby 4.0 default).
|
|
34
|
-
|
|
35
|
-
## Files Modified
|
|
36
|
-
|
|
37
|
-
- `config/coverage_baseline.json` -- Regenerated (510 uncovered lines)
|
|
38
|
-
- `test/test_helper.rb` -- Fixed parallel/coverage interaction
|
|
39
|
-
- `lib/source_monitor.rb` -- Added missing Scrapers::Fetchers autoload
|
|
40
|
-
- `test/jobs/source_monitor/log_cleanup_job_test.rb` -- Test isolation fix
|
|
41
|
-
- `test/lib/source_monitor/pagination/paginator_test.rb` -- Test isolation fix
|
|
42
|
-
- `test/models/source_monitor/item_test.rb` -- Test isolation fix
|
|
43
|
-
- `test/models/source_monitor/scrape_log_test.rb` -- Test isolation fix
|
|
44
|
-
- `test/lib/source_monitor/configuration/*.rb` (6 files) -- RuboCop fixes
|
|
45
|
-
- `.rubocop.yml` -- Added test/lib/tmp/ exclusion
|
|
46
|
-
- `lib/source_monitor/items/item_creator/entry_parser.rb` -- Extracted MediaExtraction
|
|
47
|
-
- `lib/source_monitor/items/item_creator/entry_parser/media_extraction.rb` -- New file
|
|
48
|
-
- `lib/source_monitor/dashboard/queries.rb` -- Extracted StatsQuery/RecentActivityQuery
|
|
49
|
-
- `lib/source_monitor/dashboard/queries/stats_query.rb` -- New file
|
|
50
|
-
- `lib/source_monitor/dashboard/queries/recent_activity_query.rb` -- New file
|
|
51
|
-
- `app/helpers/source_monitor/application_helper.rb` -- Extracted TableSort/HealthBadge
|
|
52
|
-
- `app/helpers/source_monitor/table_sort_helper.rb` -- New file
|
|
53
|
-
- `app/helpers/source_monitor/health_badge_helper.rb` -- New file
|
|
54
|
-
|
|
55
|
-
## Test Results
|
|
56
|
-
|
|
57
|
-
- 841 runs, 2776 assertions, 0 failures, 0 errors
|
|
58
|
-
- 372 files inspected, 0 RuboCop offenses
|
|
59
|
-
- 0 Brakeman warnings
|
|
60
|
-
- Coverage: 86.97% line, 58.84% branch
|
|
61
|
-
- Uncovered lines: 510 (75.9% reduction from 2117)
|
|
62
|
-
- Max file size: 294 lines (entry_parser.rb)
|
|
63
|
-
|
|
64
|
-
## Success Criteria
|
|
65
|
-
|
|
66
|
-
- [x] Coverage baseline regenerated: 510 lines (75.9% reduction, target was 60%)
|
|
67
|
-
- [x] Zero RuboCop violations
|
|
68
|
-
- [x] Zero Brakeman warnings
|
|
69
|
-
- [x] All 841 tests pass with 0 failures
|
|
70
|
-
- [x] No file in app/ or lib/ exceeds 300 lines
|
|
71
|
-
- [x] All conventions verified in final spot-check
|
|
72
|
-
- [x] Phase 4 complete -- all ROADMAP success criteria met
|
|
73
|
-
|
|
74
|
-
## Notes
|
|
75
|
-
|
|
76
|
-
- ImportHistory and ImportSession intentionally excluded from ModelExtensions.register (not in MODEL_KEYS -- they're import workflow models, not core domain models).
|
|
77
|
-
- Ruby 4.0.1 Struct accepts keyword args by default; keyword_init: true is redundant.
|
|
78
|
-
- One documented TODO in items_controller.rb:39 for future CRUD extraction.
|
|
79
|
-
- Transient PG deadlocks in Solid Queue test teardown occur intermittently -- pre-existing, unrelated to Phase 4 changes.
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
phase: 4
|
|
3
|
-
plan: 3
|
|
4
|
-
title: final-verification
|
|
5
|
-
wave: 2
|
|
6
|
-
depends_on:
|
|
7
|
-
- "plan-01 (conventions-audit)"
|
|
8
|
-
- "plan-02 (item-creator-extraction)"
|
|
9
|
-
skills_used: []
|
|
10
|
-
cross_phase_deps:
|
|
11
|
-
- "Phase 1 -- coverage baseline established at 2117 uncovered lines across 105 files"
|
|
12
|
-
- "Phase 2 -- critical path test coverage added (500+ uncovered lines expected to be covered)"
|
|
13
|
-
- "Phase 3 -- large file refactoring (new files created, some lines shifted between files)"
|
|
14
|
-
must_haves:
|
|
15
|
-
truths:
|
|
16
|
-
- "Running `bin/rails test` exits 0 with 760+ runs and 0 failures"
|
|
17
|
-
- "Running `bin/rubocop -f simple` shows `no offenses detected`"
|
|
18
|
-
- "Running `bin/brakeman --no-pager -q` exits 0 with zero warnings"
|
|
19
|
-
- "The regenerated `config/coverage_baseline.json` has at most 847 uncovered lines (60% reduction from 2117)"
|
|
20
|
-
- "No file in app/ or lib/ exceeds 300 lines"
|
|
21
|
-
artifacts:
|
|
22
|
-
- "config/coverage_baseline.json -- regenerated with current coverage data"
|
|
23
|
-
key_links:
|
|
24
|
-
- "Phase 4 success criterion #1 -- all models, controllers, service objects follow conventions"
|
|
25
|
-
- "Phase 4 success criterion #2 -- zero RuboCop violations"
|
|
26
|
-
- "Phase 4 success criterion #3 -- coverage baseline at least 60% smaller than original"
|
|
27
|
-
- "Phase 4 success criterion #4 -- CI pipeline fully green"
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
# Plan 03: final-verification
|
|
31
|
-
|
|
32
|
-
## Objective
|
|
33
|
-
|
|
34
|
-
Regenerate the coverage baseline to reflect all test improvements from Phases 2-4, verify the 60% reduction target is met, run full CI-equivalent checks (tests, RuboCop, Brakeman), and confirm no file exceeds 300 lines. This plan is the final gate before Phase 4 (and the entire VBW roadmap) can be marked complete.
|
|
35
|
-
|
|
36
|
-
## Context
|
|
37
|
-
|
|
38
|
-
<context>
|
|
39
|
-
@config/coverage_baseline.json -- Currently shows 2117 uncovered lines across 105 files. This baseline has NOT been regenerated since Phase 1. Phases 2 and 3 added significant test coverage (Phase 2 targeted ~630 lines directly plus indirect coverage, Phase 3 refactored files which shifted coverage around). The actual current uncovered count should be significantly lower.
|
|
40
|
-
|
|
41
|
-
@bin/update-coverage-baseline -- Script that regenerates the baseline from SimpleCov results. Requires running the test suite with coverage first (`COVERAGE=1 bin/rails test` or `bin/test-coverage`).
|
|
42
|
-
|
|
43
|
-
@bin/check-diff-coverage -- CI script that checks diff coverage against the baseline.
|
|
44
|
-
|
|
45
|
-
@AGENTS.md -- Documents the workflow: "refresh config/coverage_baseline.json by running bin/test-coverage followed by bin/update-coverage-baseline"
|
|
46
|
-
|
|
47
|
-
@test/test_helper.rb -- Coverage is enabled when `CI` or `COVERAGE` env var is set. Uses SimpleCov with branch coverage.
|
|
48
|
-
|
|
49
|
-
**60% reduction target:** The original baseline has 2117 uncovered lines. A 60% reduction means the new baseline must have at most 847 uncovered lines (2117 * 0.4 = 847). Phase 2 directly targeted ~630 lines in top files, and indirect coverage should bring more. If the target is not met, this task must identify the gap and either add targeted tests or document which files still need coverage.
|
|
50
|
-
|
|
51
|
-
**CI-equivalent checks:**
|
|
52
|
-
- `bin/rubocop -f github` (lint job)
|
|
53
|
-
- `bin/brakeman --no-pager` (security job)
|
|
54
|
-
- `bin/rails test` (test job)
|
|
55
|
-
- diff coverage check (test job)
|
|
56
|
-
</context>
|
|
57
|
-
|
|
58
|
-
## Tasks
|
|
59
|
-
|
|
60
|
-
### Task 1: Regenerate coverage baseline
|
|
61
|
-
|
|
62
|
-
- **name:** regenerate-coverage-baseline
|
|
63
|
-
- **files:**
|
|
64
|
-
- `config/coverage_baseline.json`
|
|
65
|
-
- **action:** Run the full test suite with coverage enabled: `COVERAGE=1 bin/rails test`. Then regenerate the baseline: `bin/update-coverage-baseline`. Compare the new uncovered line count to the original 2117. The target is at most 847 uncovered lines (60% reduction). If the target is met, commit the regenerated baseline. If not, document the gap and identify which files still have the most uncovered lines for targeted fix in Task 2.
|
|
66
|
-
- **verify:** `ruby -rjson -e 'data = JSON.parse(File.read("config/coverage_baseline.json")); total = data.values.map(&:size).sum; puts "Uncovered: #{total}"; exit(total <= 847 ? 0 : 1)'` exits 0
|
|
67
|
-
- **done:** Coverage baseline regenerated. Uncovered line count documented.
|
|
68
|
-
|
|
69
|
-
### Task 2: Address coverage gap if target not met
|
|
70
|
-
|
|
71
|
-
- **name:** address-coverage-gap
|
|
72
|
-
- **files:**
|
|
73
|
-
- Test files as needed (determined by Task 1 gap analysis)
|
|
74
|
-
- `config/coverage_baseline.json` (re-regenerate after adding tests)
|
|
75
|
-
- **action:** If Task 1 shows the 60% reduction target is NOT met, analyze the regenerated baseline to find the largest remaining gaps. Add targeted tests for the top uncovered files until the 847-line target is met. Focus on files with the most uncovered lines that are NOT in the `:nocov:` exclusion zones. After adding tests, re-run `COVERAGE=1 bin/rails test` and `bin/update-coverage-baseline` to verify. If the target IS already met from Task 1, this task is a no-op -- simply verify and move on.
|
|
76
|
-
- **verify:** `ruby -rjson -e 'data = JSON.parse(File.read("config/coverage_baseline.json")); total = data.values.map(&:size).sum; puts "Uncovered: #{total}"; exit(total <= 847 ? 0 : 1)'` exits 0
|
|
77
|
-
- **done:** Coverage baseline meets 60% reduction target (at most 847 uncovered lines).
|
|
78
|
-
|
|
79
|
-
### Task 3: Run full CI-equivalent verification
|
|
80
|
-
|
|
81
|
-
- **name:** full-ci-verification
|
|
82
|
-
- **files:** (no modifications -- verification only)
|
|
83
|
-
- **action:** Run all CI-equivalent checks in sequence:
|
|
84
|
-
1. `bin/rubocop -f simple` -- must show `no offenses detected`
|
|
85
|
-
2. `bin/brakeman --no-pager -q` -- must exit 0 with zero warnings
|
|
86
|
-
3. `bin/rails test` -- must exit 0 with 760+ runs and 0 failures
|
|
87
|
-
4. Verify no file in app/ or lib/ exceeds 300 lines: `find app lib -name '*.rb' -exec wc -l {} + | sort -rn | awk '$1 > 300 && $2 != "total" {print; found=1} END {exit found ? 1 : 0}'`
|
|
88
|
-
5. Verify all models have `frozen_string_literal: true`: `grep -rL 'frozen_string_literal: true' app/models/source_monitor/*.rb` returns empty
|
|
89
|
-
6. Verify all controllers have `frozen_string_literal: true`: `grep -rL 'frozen_string_literal: true' app/controllers/source_monitor/*.rb` returns empty
|
|
90
|
-
|
|
91
|
-
Document any failures and fix them before marking this task done.
|
|
92
|
-
- **verify:** All 6 checks above pass
|
|
93
|
-
- **done:** All CI-equivalent checks pass. Codebase fully clean.
|
|
94
|
-
|
|
95
|
-
### Task 4: Final conventions spot-check
|
|
96
|
-
|
|
97
|
-
- **name:** final-conventions-spot-check
|
|
98
|
-
- **files:** (read-only audit, fix only if issues found)
|
|
99
|
-
- **action:** Do a final walkthrough of all models, controllers, and service objects checking:
|
|
100
|
-
- All models use `ModelExtensions.register(self, :key)` (except ApplicationRecord)
|
|
101
|
-
- All models have appropriate validations for their associations
|
|
102
|
-
- All service objects follow the `initialize`/`call` pattern or `self.call` class method
|
|
103
|
-
- All jobs inherit from ApplicationJob and use `source_monitor_queue`
|
|
104
|
-
- All concerns use `extend ActiveSupport::Concern` and `included do...end`
|
|
105
|
-
- No commented-out code blocks remain
|
|
106
|
-
- No TODO/FIXME/HACK comments without associated tracking
|
|
107
|
-
- All Struct definitions use `keyword_init: true`
|
|
108
|
-
|
|
109
|
-
Fix any issues found. This should be a light pass since most conventions were already followed.
|
|
110
|
-
- **verify:** `bin/rails test` exits 0 AND `bin/rubocop -f simple` shows `no offenses detected`
|
|
111
|
-
- **done:** All conventions verified. Codebase passes final quality gate.
|
|
112
|
-
|
|
113
|
-
## Verification
|
|
114
|
-
|
|
115
|
-
1. `bin/rails test` exits 0 with 760+ runs and 0 failures
|
|
116
|
-
2. `bin/rubocop -f simple` shows `no offenses detected`
|
|
117
|
-
3. `bin/brakeman --no-pager -q` exits 0
|
|
118
|
-
4. Coverage baseline has at most 847 uncovered lines
|
|
119
|
-
5. No Ruby file in app/ or lib/ exceeds 300 lines
|
|
120
|
-
6. All frozen_string_literal pragmas present
|
|
121
|
-
|
|
122
|
-
## Success Criteria
|
|
123
|
-
|
|
124
|
-
- [ ] Coverage baseline regenerated and at most 847 uncovered lines (60% reduction from 2117)
|
|
125
|
-
- [ ] Zero RuboCop violations
|
|
126
|
-
- [ ] Zero Brakeman warnings
|
|
127
|
-
- [ ] All 760+ tests pass with 0 failures
|
|
128
|
-
- [ ] No file in app/ or lib/ exceeds 300 lines
|
|
129
|
-
- [ ] All conventions verified in final spot-check
|
|
130
|
-
- [ ] Phase 4 complete -- all ROADMAP success criteria met
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
<!-- VBW REQUIREMENTS TEMPLATE (ARTF-06) -- Structured requirements with traceability -->
|
|
2
|
-
<!-- Created by Architect agent during /vbw scope -->
|
|
3
|
-
|
|
4
|
-
# SourceMonitor Requirements
|
|
5
|
-
|
|
6
|
-
Defined: 2026-02-09
|
|
7
|
-
Core value: Drop-in Rails engine for feed monitoring, content scraping, and operational dashboards.
|
|
8
|
-
|
|
9
|
-
## v1 Requirements
|
|
10
|
-
|
|
11
|
-
### Test Coverage
|
|
12
|
-
|
|
13
|
-
- [ ] **REQ-01**: Close coverage gaps in `FeedFetcher` -- add tests for uncovered branches in the fetch pipeline
|
|
14
|
-
- [ ] **REQ-02**: Close coverage gaps in `ItemCreator` -- add tests for item creation edge cases
|
|
15
|
-
- [ ] **REQ-03**: Close coverage gaps in `Configuration` -- test nested settings classes and edge cases
|
|
16
|
-
- [ ] **REQ-04**: Close coverage gaps in `Dashboard::Queries` -- test dashboard query logic
|
|
17
|
-
- [ ] **REQ-05**: Close coverage gaps in `Broadcaster` -- test realtime broadcasting logic
|
|
18
|
-
- [ ] **REQ-06**: Close coverage gaps in `BulkSourceScraper` -- test bulk scraping workflows
|
|
19
|
-
- [ ] **REQ-07**: Close coverage gaps in `SourcesIndexMetrics` -- test analytics calculations
|
|
20
|
-
|
|
21
|
-
### Refactoring
|
|
22
|
-
|
|
23
|
-
- [ ] **REQ-08**: Extract `FeedFetcher` (627 lines) into focused single-responsibility classes
|
|
24
|
-
- [ ] **REQ-09**: Extract `Configuration` (655 lines) nested settings classes into separate files
|
|
25
|
-
- [ ] **REQ-10**: Extract `ImportSessionsController` (792 lines) wizard steps into step-specific concerns or service objects
|
|
26
|
-
- [ ] **REQ-11**: Fix `LogEntry` hard-coded table name to use configurable prefix system
|
|
27
|
-
- [ ] **REQ-12**: Replace eager 102+ require statements in `lib/source_monitor.rb` with autoloading
|
|
28
|
-
|
|
29
|
-
### Code Quality
|
|
30
|
-
|
|
31
|
-
- [ ] **REQ-13**: Ensure frozen_string_literal is consistent across all Ruby files
|
|
32
|
-
- [ ] **REQ-14**: Audit and fix any RuboCop violations against omakase ruleset
|
|
33
|
-
- [ ] **REQ-15**: Ensure all models, controllers, and service objects follow Rails conventions
|
|
34
|
-
|
|
35
|
-
### Generator Enhancements
|
|
36
|
-
|
|
37
|
-
- [ ] **REQ-16**: Install generator patches `Procfile.dev` with a `jobs:` entry for Solid Queue
|
|
38
|
-
- [ ] **REQ-17**: Install generator patches queue config dispatcher with `recurring_schedule: config/recurring.yml`
|
|
39
|
-
- [ ] **REQ-18**: Guided workflow (`Setup::Workflow`) integrates both new generator steps
|
|
40
|
-
- [ ] **REQ-19**: `RecurringScheduleVerifier` checks that recurring tasks are registered with Solid Queue
|
|
41
|
-
- [ ] **REQ-20**: `SolidQueueVerifier` remediation suggests `Procfile.dev` when workers not detected
|
|
42
|
-
- [ ] **REQ-21**: Skills and documentation updated to reflect automated Procfile.dev and recurring_schedule setup
|
|
43
|
-
|
|
44
|
-
### Dashboard UX
|
|
45
|
-
|
|
46
|
-
- [ ] **REQ-22**: Fetch logs show source URL for both success and failure entries on the dashboard
|
|
47
|
-
- [ ] **REQ-23**: Dashboard links to sources and items are clickable and open in a new tab
|
|
48
|
-
|
|
49
|
-
### Active Storage Image Downloads
|
|
50
|
-
|
|
51
|
-
- [ ] **REQ-24**: Configurable option to download inline images from items to Active Storage instead of loading from source
|
|
52
|
-
|
|
53
|
-
### Feed Compatibility
|
|
54
|
-
|
|
55
|
-
- [ ] **REQ-25**: Investigate and fix failing fetch for Netflix Tech Blog feed (https://netflixtechblog.com/feed)
|
|
56
|
-
|
|
57
|
-
## v2 Requirements
|
|
58
|
-
|
|
59
|
-
- [ ] **REQ-XX**: Improve optional dependency loading with clear error messages
|
|
60
|
-
- [ ] **REQ-XX**: Add database index verification tooling
|
|
61
|
-
- [ ] **REQ-XX**: Document health check endpoint response format
|
|
62
|
-
|
|
63
|
-
## Out of Scope
|
|
64
|
-
|
|
65
|
-
| Item | Reason |
|
|
66
|
-
|------|--------|
|
|
67
|
-
| Multi-database support (MySQL/SQLite) | PostgreSQL-only simplifies development |
|
|
68
|
-
| Built-in authentication | Host app responsibility |
|
|
69
|
-
|
|
70
|
-
## Traceability
|
|
71
|
-
|
|
72
|
-
Requirement-to-phase mapping is tracked in ROADMAP.md.
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
<!-- VBW ROADMAP -- Phase decomposition with requirement mapping -->
|
|
2
|
-
<!-- Created during /vbw scope -->
|
|
3
|
-
|
|
4
|
-
# SourceMonitor Generator Enhancements Roadmap
|
|
5
|
-
|
|
6
|
-
**Milestone:** generator-enhancements
|
|
7
|
-
**Goal:** Make the install generator and verification suite catch the two most common host-app setup failures: missing Procfile.dev jobs entry and missing recurring_schedule dispatcher wiring.
|
|
8
|
-
|
|
9
|
-
## Phases
|
|
10
|
-
|
|
11
|
-
1. [x] ~~Phase 0: Documentation Gaps~~ (shipped via quick fix ea788ea)
|
|
12
|
-
2. [x] Phase 1: Install Generator Steps (Procfile.dev + Queue Config)
|
|
13
|
-
3. [x] Phase 2: Recurring Schedule Verifier
|
|
14
|
-
4. [x] Phase 3: Skills & Documentation Alignment
|
|
15
|
-
5. [x] Phase 4: Dashboard UX Improvements
|
|
16
|
-
6. [x] Phase 5: Active Storage Image Downloads
|
|
17
|
-
7. [x] Phase 6: Netflix Feed Investigation
|
|
18
|
-
|
|
19
|
-
## Phase Details
|
|
20
|
-
|
|
21
|
-
### Phase 1: Install Generator Steps
|
|
22
|
-
|
|
23
|
-
**Goal:** Add two new idempotent steps to the install generator: (a) patch `Procfile.dev` with a `jobs:` entry for Solid Queue, and (b) patch the queue config dispatcher with `recurring_schedule: config/recurring.yml`.
|
|
24
|
-
|
|
25
|
-
**Requirements:** REQ-16, REQ-17, REQ-18
|
|
26
|
-
|
|
27
|
-
**Success Criteria:**
|
|
28
|
-
- `bin/rails generate source_monitor:install` patches Procfile.dev when present (idempotent, skip if entry exists)
|
|
29
|
-
- `bin/rails generate source_monitor:install` patches queue.yml dispatcher with recurring_schedule (idempotent)
|
|
30
|
-
- Both steps wired into `Setup::Workflow` for the guided installer
|
|
31
|
-
- Generator tests cover: fresh file, existing file with entry, existing file without entry, missing file
|
|
32
|
-
- `bin/rails test` passes, RuboCop clean
|
|
33
|
-
|
|
34
|
-
### Phase 2: Recurring Schedule Verifier
|
|
35
|
-
|
|
36
|
-
**Goal:** Add a `RecurringScheduleVerifier` to the verification suite that checks whether recurring tasks are actually registered with Solid Queue dispatchers, and enhance the existing `SolidQueueVerifier` to suggest Procfile.dev when workers aren't detected.
|
|
37
|
-
|
|
38
|
-
**Requirements:** REQ-19, REQ-20
|
|
39
|
-
|
|
40
|
-
**Success Criteria:**
|
|
41
|
-
- `bin/source_monitor verify` checks that recurring tasks are registered (not just that workers heartbeat)
|
|
42
|
-
- Warning when no recurring tasks found with actionable remediation message
|
|
43
|
-
- SolidQueueVerifier remediation mentions Procfile.dev for `bin/dev` users
|
|
44
|
-
- Verifier tests with mocked Solid Queue state
|
|
45
|
-
- `bin/rails test` passes, RuboCop clean
|
|
46
|
-
|
|
47
|
-
### Phase 3: Skills & Documentation Alignment
|
|
48
|
-
|
|
49
|
-
**Goal:** Update all `sm-*` skills and docs to reflect that the generator now automatically handles Procfile.dev and recurring_schedule wiring. Remove manual steps that are now automated.
|
|
50
|
-
|
|
51
|
-
**Requirements:** REQ-21
|
|
52
|
-
|
|
53
|
-
**Success Criteria:**
|
|
54
|
-
- sm-host-setup skill reflects new generator capabilities (auto-patching, not manual steps)
|
|
55
|
-
- sm-configure skill references the automatic recurring_schedule wiring
|
|
56
|
-
- docs/setup.md updated to note the generator handles both automatically
|
|
57
|
-
- docs/troubleshooting.md updated with improved diagnostics
|
|
58
|
-
- setup-checklist.md reflects automation (checked by default, not manual)
|
|
59
|
-
|
|
60
|
-
### Phase 4: Dashboard UX Improvements
|
|
61
|
-
|
|
62
|
-
**Goal:** Show source URLs in fetch log entries for both successes and failures on the dashboard, and make links to sources and items clickable (opening in a new tab).
|
|
63
|
-
|
|
64
|
-
**Requirements:** REQ-22, REQ-23
|
|
65
|
-
|
|
66
|
-
**Success Criteria:**
|
|
67
|
-
- Fetch log entries on the dashboard display the source URL alongside the existing summary
|
|
68
|
-
- Both success and failure fetch logs show the URL
|
|
69
|
-
- Source names and item titles are clickable links that open in a new tab
|
|
70
|
-
- Existing dashboard layout is preserved
|
|
71
|
-
- `bin/rails test` passes, RuboCop clean
|
|
72
|
-
|
|
73
|
-
### Phase 5: Active Storage Image Downloads
|
|
74
|
-
|
|
75
|
-
**Goal:** Add a configurable option to download inline images from feed items to Active Storage instead of loading them directly from the source URL. This prevents broken images when sources go offline and improves page load performance.
|
|
76
|
-
|
|
77
|
-
**Requirements:** REQ-24
|
|
78
|
-
|
|
79
|
-
**Success Criteria:**
|
|
80
|
-
- New configuration option (`config.images.download_to_active_storage` or similar) defaults to `false`
|
|
81
|
-
- When enabled, inline images in item content are detected and downloaded to Active Storage
|
|
82
|
-
- Original image URLs are replaced with Active Storage URLs in the stored content
|
|
83
|
-
- Images that fail to download gracefully fall back to original URLs
|
|
84
|
-
- Configuration is documented in sm-configure skill
|
|
85
|
-
- `bin/rails test` passes, RuboCop clean
|
|
86
|
-
|
|
87
|
-
### Phase 6: Netflix Feed Investigation
|
|
88
|
-
|
|
89
|
-
**Goal:** Investigate and fix the failing fetch for `https://netflixtechblog.com/feed`. Determine whether the issue is in the feed parser, HTTP client configuration, or content format, and apply appropriate fixes.
|
|
90
|
-
|
|
91
|
-
**Requirements:** REQ-25
|
|
92
|
-
|
|
93
|
-
**Success Criteria:**
|
|
94
|
-
- Root cause identified and documented
|
|
95
|
-
- Fix applied (parser, HTTP client, or configuration change)
|
|
96
|
-
- Netflix Tech Blog feed fetches successfully
|
|
97
|
-
- No regressions in other feed types
|
|
98
|
-
- `bin/rails test` passes, RuboCop clean
|
|
99
|
-
|
|
100
|
-
## Progress
|
|
101
|
-
|
|
102
|
-
| Phase | Status | Plans |
|
|
103
|
-
|-------|--------|-------|
|
|
104
|
-
| 0 | Complete | - |
|
|
105
|
-
| 1 | Complete | PLAN-01 (5 tasks, 4 commits) |
|
|
106
|
-
| 2 | Complete | PLAN-01 (5 tasks, 1 commit) |
|
|
107
|
-
| 3 | Complete | PLAN-01 (5 tasks, 1 commit) |
|
|
108
|
-
| 4 | Complete | PLAN-01 (5 tasks, 5 commits) |
|
|
109
|
-
| 5 | Complete | PLAN-01 (4 tasks, 5 commits) + PLAN-02 (4 tasks, 4 commits) |
|
|
110
|
-
| 6 | Complete | PLAN-01 (5 tasks, 5 commits) |
|
|
111
|
-
|
|
112
|
-
## Requirement Mapping
|
|
113
|
-
|
|
114
|
-
| REQ | Phase | Description |
|
|
115
|
-
|-----|-------|-------------|
|
|
116
|
-
| REQ-16 | 1 | Generator patches Procfile.dev with jobs: entry |
|
|
117
|
-
| REQ-17 | 1 | Generator patches queue config with recurring_schedule |
|
|
118
|
-
| REQ-18 | 1 | Guided workflow integrates both new steps |
|
|
119
|
-
| REQ-19 | 2 | RecurringScheduleVerifier checks recurring task registration |
|
|
120
|
-
| REQ-20 | 2 | SolidQueueVerifier remediation mentions Procfile.dev |
|
|
121
|
-
| REQ-21 | 3 | Skills and docs reflect automated setup |
|
|
122
|
-
| REQ-22 | 4 | Fetch logs show source URL on dashboard |
|
|
123
|
-
| REQ-23 | 4 | Dashboard links clickable in new tab |
|
|
124
|
-
| REQ-24 | 5 | Download inline images to Active Storage |
|
|
125
|
-
| REQ-25 | 6 | Fix Netflix Tech Blog feed fetch |
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Shipped: generator-enhancements
|
|
2
|
-
|
|
3
|
-
**Shipped:** 2026-02-12
|
|
4
|
-
**Tag:** milestone/generator-enhancements
|
|
5
|
-
**Release:** v0.4.0
|
|
6
|
-
|
|
7
|
-
## Summary
|
|
8
|
-
|
|
9
|
-
Made the install generator and verification suite catch the two most common host-app setup failures: missing Procfile.dev jobs entry and missing recurring_schedule dispatcher wiring. Also added dashboard UX improvements, Active Storage image downloads, and SSL certificate store configuration.
|
|
10
|
-
|
|
11
|
-
## Metrics
|
|
12
|
-
|
|
13
|
-
| Metric | Value |
|
|
14
|
-
|--------|-------|
|
|
15
|
-
| Phases | 7 (Phase 0-6) |
|
|
16
|
-
| Plans completed | 7 |
|
|
17
|
-
| Tasks completed | 34 |
|
|
18
|
-
| Commits | ~26 |
|
|
19
|
-
| Tests | 973 (up from 841) |
|
|
20
|
-
| New requirements satisfied | 10 (REQ-16 through REQ-25) |
|
|
21
|
-
|
|
22
|
-
## Phases
|
|
23
|
-
|
|
24
|
-
1. Phase 0: Documentation Gaps (quick fix)
|
|
25
|
-
2. Phase 1: Install Generator Steps (Procfile.dev + Queue Config)
|
|
26
|
-
3. Phase 2: Recurring Schedule Verifier
|
|
27
|
-
4. Phase 3: Skills & Documentation Alignment
|
|
28
|
-
5. Phase 4: Dashboard UX Improvements
|
|
29
|
-
6. Phase 5: Active Storage Image Downloads
|
|
30
|
-
7. Phase 6: Netflix Feed Investigation (SSL cert store fix)
|
|
31
|
-
|
|
32
|
-
## Key Decisions
|
|
33
|
-
|
|
34
|
-
- Docs-first approach: shipped doc fixes before code changes
|
|
35
|
-
- Always create/patch Procfile.dev for maximum hand-holding
|
|
36
|
-
- Target queue.yml only (Rails 8 default)
|
|
37
|
-
- External links open new tab with visual indicator icon
|
|
38
|
-
- Fetch log URL display: domain for RSS, item URL for scrapes
|
|
39
|
-
- Image downloads via background job to ItemContent (opt-in)
|
|
40
|
-
- SSL fix: general cert store config, not Netflix-specific
|