Supervised source candidates: stage, list, promote, reject

- New source_candidates staging table (status suggested/quarantined/rejected/
  promoted, preview_json snapshot) so untrusted/suggested feeds stay out of the
  real ingestion path until reviewed.
- sources.py: save_candidate (re-preview never revives a curator's rejection),
  list_candidates, reject_candidate, promote_candidate (copies into sources,
  inactive by default — active on approval; never automatic).
- CLI: suggest-source / list-candidates / promote-candidate / reject-candidate.
- API: read-only GET /api/candidates (writes stay CLI-only — no unauthenticated
  public write surface yet).
- Fix deprecated ElementTree truth-value test in _parse_rss.
- Tests: candidate lifecycle (save/list/promote/reject, status preservation,
  name derivation) — 51 total.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jay
2026-05-30 19:52:40 +00:00
parent 95195daff8
commit aa4125ddec
7 changed files with 282 additions and 7 deletions
+12 -5
View File
@@ -18,6 +18,10 @@ python3 -m goodnews classify --limit 10 --base-url http://127.0.0.1:1234/v1 --mo
python3 -m goodnews dedup --base-url http://127.0.0.1:1234/v1
python3 -m goodnews check-feeds
python3 -m goodnews preview-source https://example.com/feed/ --classify
python3 -m goodnews suggest-source https://example.com/feed/ --name "Example" --classify
python3 -m goodnews list-candidates
python3 -m goodnews promote-candidate 1 # copies into sources (inactive by default)
python3 -m goodnews reject-candidate 1
python3 -m goodnews build-brief --date 2026-05-27 --replace
python3 -m goodnews show-brief
python3 -m goodnews list-recent --limit 10
@@ -101,6 +105,7 @@ Endpoints:
- `GET /api/brief?date=&limit=` — a daily brief (latest if no date)
- `GET /api/brief-dates` — available brief dates
- `GET /api/source-preview?url=&classify=` — read-only scored sample of a feed (vet before adding)
- `GET /api/candidates?status=` — staged source candidates (read-only; curation is CLI-only for now)
- `GET /docs` — interactive OpenAPI documentation
The ingestion CLI stays pure-stdlib; only the `web` extra pulls in FastAPI/uvicorn,
@@ -186,11 +191,13 @@ and site, scheduled `cycle` via systemd, a pytest suite, and device-local Calm F
Still ahead:
1. **Supervised source pipeline**read-only preview is done (`preview-source` /
`/api/source-preview`: freshness, acceptance rate, topic/flavor mix,
cortisol/ragebait/PR averages, example items). Still ahead: add a previewed
source to *quarantine*, and auto-degrade stale/rejecting feeds (advisory, never
auto-blocking).
1. **Supervised source pipeline**preview + staging are done: `suggest-source`
previews a feed and stages it in the `source_candidates` table (status
suggested/quarantined/rejected/promoted); `promote-candidate` copies it into
`sources` (inactive by default — active on approval); promotion is never
automatic. Still ahead: advisory auto-degrade of stale/rejecting feeds (flag
for review, never auto-block), and an authenticated POST surface so the website
can accept public suggestions once accounts exist.
2. **Learned "Less like this" weighting** — replace the interim flavor-pause with
real preference down-ranking.
3. **Corpus rebalancing** — add calm/feelgood sources (currently science-heavy).