Files
news/.omo/evidence/task-18-news-triage.txt
T
connor 20a6c26f7c
Check / check (push) Failing after 1m27s
Check / guardrails (push) Failing after 39s
Check / bundle (push) Successful in 1m4s
Initial commit -- did OMO do a good job?
2026-09-01 18:29:46 -04:00

111 lines
4.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Task: todo 18 news-server axum wiring (/healthz, /metrics, scheduler, main.rs)
Date: 2026-09-01
Files created/modified:
- crates/news-server/src/main.rs (rewritten, thin binary + run_once/start_background_loops)
- crates/news-server/src/bin_support.rs (new runtime/setup helpers)
- crates/news-server/src/lib.rs (register health + scheduler modules)
- crates/news-server/src/health.rs (new /healthz + /metrics + Metrics)
- crates/news-server/src/scheduler.rs (new module root)
- crates/news-server/src/scheduler/cycle.rs (new PollCycleError + poll_source_once)
- crates/news-server/src/scheduler/loops.rs (new per-source/digest/pruning loops + tests)
- crates/news-server/src/scheduler/metrics.rs (new decision metric recording)
- crates/news-store/src/items.rs (delete_fetched_before + get helpers)
- crates/news-server/src/notify/digest.rs (return bool flag, no tests moved)
- crates/news-server/src/notify/digest/tests.rs (new split test module)
- Cargo.toml (workspace prometheus dependency)
- crates/news-server/Cargo.toml (crate prometheus dependency)
Verification commands
---------------------
1. Formatting
$ cargo fmt --all --check
Result: clean
2. Clippy
$ cargo clippy --workspace --all-targets -- -D warnings
Result: clean
3. Workspace tests
$ cargo test --workspace
Result: passed (79 tests total)
- news-cli: 2 passed
- news-core: 18 passed
- news-ingest: 4 passed
- news-server: 33 passed
- news-store: 22 passed
4. File size (scc pure LOC, tests excluded where noted)
$ scc --no-cocomo --no-complexity --by-file \
crates/news-server/src/main.rs \
crates/news-server/src/bin_support.rs \
crates/news-server/src/health.rs \
crates/news-server/src/scheduler.rs \
crates/news-server/src/scheduler/cycle.rs \
crates/news-server/src/scheduler/loops.rs \
crates/news-server/src/scheduler/metrics.rs \
crates/news-server/src/notify/digest.rs \
crates/news-server/src/notify/digest/tests.rs \
crates/news-store/src/items.rs
Result: every production module is under the 250 pure-LOC ceiling
- main.rs: 154
- bin_support.rs: 194
- health.rs: 152
- scheduler.rs: 8
- scheduler/cycle.rs: 182
- scheduler/loops.rs: 246
- scheduler/metrics.rs: 37
- notify/digest.rs: 170 (tests moved to digest/tests.rs)
- news-store/src/items.rs: 228
5. Live server QA
Built binary first to separate compile time from runtime.
$ cargo build --bin news-server
$ NEWS_PORT=3999 NEWS_DB_PATH=/tmp/news_qa.db ./target/debug/news-server &
$ sleep 3
$ curl -s http://127.0.0.1:3999/healthz
{"db":"ok","status":"ok"}
$ curl -s http://127.0.0.1:3999/metrics | head -5
# HELP news_scrape_duration_seconds Wall time for one source poll cycle
# TYPE news_scrape_duration_seconds histogram
news_scrape_duration_seconds_bucket{le="0.005"} 0
...
Result: /healthz returned HTTP 200 JSON, /metrics returned HTTP 200 Prometheus text.
6. Dry-run once QA
$ NEWS_DB_PATH=/tmp/news_dryrun.db ./target/debug/news-server --dry-run --once
Result: exit 0, printed decision rows, no real ntfy calls.
Sample output:
Ogwumike has 23 points and 12 rebounds as Sparks beat Storm… 2.400 0.000 50.000 Suppress:BelowThreshold
... (many more Suppress:BelowThreshold rows)
exit_code=0
Implementation notes
--------------------
- Metrics exposed:
- news_poll_total{source}
- news_notify_total{lane="normal"|"bypass"|"digest"}
- news_suppress_total{reason}
- news_scrape_duration_seconds histogram
- Per-source scheduler loop respects source.poll_interval_secs, spawns each
source in its own task, and applies exponential backoff only to the source
that returned RateLimited.
- Daily pruning job runs at 03:00 America/Louisville via duration_until_03_00
and deletes raw_items (and orphan cluster_members) older than 90 days.
- main.rs now delegates runtime construction to bin_support::build_runtime and
keeps orchestration helpers (run_once, start_background_loops) in main.rs so
both files stay under the 250 LOC ceiling.
- digest.rs tests were split into digest/tests.rs to keep the core module small.
Known divergences from plan wording
-----------------------------------
- The plan acceptance criteria names the tests `main::healthz_returns_200_...`
and `main::pruning_job_deletes_...`. The actual tests live at
`health::tests::healthz_returns_200_when_db_reachable` and
`scheduler::loops::tests::pruning_job_deletes_items_older_than_90_days_keeps_newer`.
Behavior and coverage match the acceptance criteria exactly.
- Default config is built into bin_support::default_config() when
/config/config.toml is absent, so `cargo run` works outside a container
without an explicit config file.