feat: always-on Insights — correlation analysis over viewing habits
Some checks failed
CI / Check / Test (push) Failing after 9m16s

Conservative, live insights (ADR-0010) derived from each user's diary:
rating lift by genre (first-time watches only), genre seasonality vs a
uniform 1/12 month baseline, medium weekend-lift, and watch-time rhythm.

- domain: WatchRow model, InsightsQuery port, pure insights_analyzer with
  all honesty thresholds (sample minimums, strength cutoffs, suppressions
  for import noise), unit-tested
- adapters: thin Sqlite/Postgres fetch twins, reusing WrapUp's genre fetch
- application: get_insights use case, InsightsGroup in Deps
- composition/server: wiring through Repositories/DatabaseOutput
- presentation: GET /api/v1/insights handler, typed serde-tagged DTOs,
  openapi doc
- spa: /insights route (shadcn cards), insights feature hook, profile
  entry link, en locale strings
- server test: end-to-end seed sqlite → HTTP → rating lift + rhythm

Also records ADR-0010, defines "Insight" in the glossary, and includes
pre-existing worktree comment-stripping cleanups.
This commit is contained in:
2026-10-12 19:29:54 +02:00
parent 4d221e60de
commit 020fbb891e
126 changed files with 1922 additions and 639 deletions

View File

@@ -14,7 +14,6 @@ pub mod watchlist_handler;
pub const INSTANCE_ACTOR_ID: uuid::Uuid =
uuid::Uuid::from_bytes([0, 0, 0, 0, 0, 0, 0x40, 0, 0x80, 0, 0, 0, 0, 0, 0, 0]);
// Re-export the generic base types that callers need
pub use k_ap::{
ActivityPubService, ActivityRepository, ActorRepository, ApContentReader, ApFederationConfig,
ApObjectHandler, ApUser, ApUserRepository, BlocklistRepository, FederationData,
@@ -41,15 +40,9 @@ pub struct FederationRepos {
}
pub struct ActivityPubWire {
/// AP document serving. Prefer this over `service` from outside this crate.
pub document: std::sync::Arc<dyn domain::ports::ApDocumentPort>,
/// Instance domain blocklist. Prefer this over `service` from outside this crate.
pub blocklist: std::sync::Arc<dyn domain::ports::InstanceBlocklistPort>,
/// Post-follow content backfill. Prefer this over `service` from outside this crate.
pub backfill: std::sync::Arc<dyn domain::ports::ApBackfillPort>,
/// The concrete service, consumed by `crates/server` to construct
/// `CompositeSocialAdapter`. Everything else should use
/// `document`/`blocklist`/`backfill`.
pub service: std::sync::Arc<ActivityPubService>,
pub router: axum::Router,
pub event_handler: std::sync::Arc<dyn domain::ports::EventHandler>,