Wire XGBoost ML model into review UI #65

Merged
coding-agent-marvin8 merged 0 commits from refs/pull/65/head into main 2026-07-04 02:35:40 +00:00
coding-agent-marvin8 commented 2026-07-03 09:26:08 +00:00 (Migrated from codeberg.org)

Summary

  • Adds ml_confidence_score column to posts (nullable float, scored at fetch time by XGBoost classifier)
  • New MLInferenceService singleton loads model artifacts at startup; gracefully degrades when absent
  • Review queue defaults to uncertainty-first ordering when model loaded (ABS(score - 0.5) ASC, NULLs last)
  • Missing-model banner and colour-coded ML confidence badge (green ≥ 0.7 / amber 0.4–0.6 / red ≤ 0.3) in review UI
  • ML confidence range filter (0.0–1.0) with NULL pass-through, combinable with spam score filter
  • Nightly retraining cron job (02:00) in StreamScheduler — skips if < 500 rows, backs up existing artifacts as .prev, offloads CPU work with asyncio.to_thread

Closes #64

## Summary - Adds `ml_confidence_score` column to posts (nullable float, scored at fetch time by XGBoost classifier) - New `MLInferenceService` singleton loads model artifacts at startup; gracefully degrades when absent - Review queue defaults to uncertainty-first ordering when model loaded (`ABS(score - 0.5) ASC`, NULLs last) - Missing-model banner and colour-coded ML confidence badge (green ≥ 0.7 / amber 0.4–0.6 / red ≤ 0.3) in review UI - ML confidence range filter (0.0–1.0) with NULL pass-through, combinable with spam score filter - Nightly retraining cron job (02:00) in StreamScheduler — skips if < 500 rows, backs up existing artifacts as `.prev`, offloads CPU work with `asyncio.to_thread` Closes #64
coding-agent-marvin8 commented 2026-07-04 01:28:28 +00:00 (Migrated from codeberg.org)

Re: pickle deserialization without integrity verification (WuMing HIGH)

Valid finding — load_artifacts calls joblib.load on user-controlled file paths, and joblib uses pickle internally.

In this deployment context the threat model is fairly narrow: an attacker needs write access to the mounted models volume. If they have that, they likely already have container exec or FS access that yields more direct attack paths. The models are generated by this application itself (the same service writes at 02:00, then reads at startup), so the trust chain is: application trains → application loads.

That said, the concern is real. On serialisation format alternatives:

  • SafeTensors — not applicable; it serialises tensor buffers, not sklearn Pipeline objects or TF-IDF vocabulary dicts
  • ONNX — possible for the XGBoost step via skl2onnx, but adds non-trivial dependency weight and the TF-IDF vocabulary round-trip through ONNX is awkward; disproportionate for a hobby project

More appropriate mitigations for this deployment pattern:

  1. File permissions — models directory owned by the service user, not writable by other processes; or mount the volume read-only at container start and remount rw only during the nightly retraining job
  2. SHA-256 sidecar — after save_artifacts, write a .sha256 file; verify it before load_artifacts; this catches race-condition tampering between the training write and the load call

Will track as a follow-up issue rather than adding complexity to this PR.

Re: pickle deserialization without integrity verification (WuMing HIGH) Valid finding — `load_artifacts` calls `joblib.load` on user-controlled file paths, and joblib uses pickle internally. In this deployment context the threat model is fairly narrow: an attacker needs write access to the mounted models volume. If they have that, they likely already have container exec or FS access that yields more direct attack paths. The models are generated by this application itself (the same service writes at 02:00, then reads at startup), so the trust chain is: application trains → application loads. That said, the concern is real. On serialisation format alternatives: - **SafeTensors** — not applicable; it serialises tensor buffers, not sklearn `Pipeline` objects or TF-IDF vocabulary dicts - **ONNX** — possible for the XGBoost step via `skl2onnx`, but adds non-trivial dependency weight and the TF-IDF vocabulary round-trip through ONNX is awkward; disproportionate for a hobby project More appropriate mitigations for this deployment pattern: 1. **File permissions** — models directory owned by the service user, not writable by other processes; or mount the volume read-only at container start and remount rw only during the nightly retraining job 2. **SHA-256 sidecar** — after `save_artifacts`, write a `.sha256` file; verify it before `load_artifacts`; this catches race-condition tampering between the training write and the load call Will track as a follow-up issue rather than adding complexity to this PR.
coding-agent-marvin8 commented 2026-07-04 01:32:17 +00:00 (Migrated from codeberg.org)

Re: ML_INTEGRATION_GUIDE.md checklist

Good catch — those three items (Alembic migration, model inference in review UI, nightly retraining) are all done in this PR. Committed d09901a ticking them off, also updated the status header from "not started" to "in progress" and corrected the Inference architecture line which still said "not yet wired into the web app".

The fourth item (per-stream model thresholds) remains open — not in scope for this PR.

Re: ML_INTEGRATION_GUIDE.md checklist Good catch — those three items (Alembic migration, model inference in review UI, nightly retraining) are all done in this PR. Committed `d09901a` ticking them off, also updated the status header from "not started" to "in progress" and corrected the Inference architecture line which still said "not yet wired into the web app". The fourth item (per-stream model thresholds) remains open — not in scope for this PR.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
marvin8/dujiangyan!65
No description provided.