Implementerer automatisk A/B-testing for forside-varianter:
- PG-migrasjon 012: ab_events-tabell for impression/klikk-logging
med hour_of_week (0-167) for tidspunkt-normalisering
- Variant-rotasjon: ab_select() velger tilfeldig blant testing-varianter
ved forside-rendering, winner prioriteres, retired filtreres bort
- Impression-logging: asynkron fire-and-forget ved forside-serve
(både cache-hit og -miss), lagres i ab_events
- Klikk-attribusjon: artikkelbesøk sjekker forside-cache for aktive
AB-varianter og logger klikk. Eksplisitt tracking via
GET /pub/{slug}/t/{article_id}?v={edge_id}
- Periodisk evaluator (300s intervall): z-test for proporsjoner
(p < 0.05), minimum 100 impressions per variant, oppdaterer
edge-metadata (ab_status, impressions, clicks, ctr)
- Redaktør-overstyring: POST /intentions/ab_override markerer
valgt variant som winner, andre som retired (krever owner/admin)
- Auto-initialisering: maybe_start_ab_test() setter ab_status=testing
automatisk når >1 variant av samme type opprettes
Alle 42 tester passerer inkludert 3 nye z-test-tester.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
37 lines
1.6 KiB
SQL
37 lines
1.6 KiB
SQL
-- A/B-testing: impression/click-logging for presentasjonselement-varianter.
|
|
--
|
|
-- Når en artikkel har flere varianter av tittel/summary/og_image-noder,
|
|
-- roterer maskinrommet mellom dem på forsiden og logger visninger/klikk.
|
|
-- Etter statistisk signifikans markeres vinneren i edge-metadata.
|
|
--
|
|
-- Ref: docs/concepts/publisering.md § "Automatisk A/B-testing"
|
|
-- Oppgave: 14.17
|
|
|
|
-- Event-logg: hvert impression/klikk logges individuelt for tid-normalisering.
|
|
CREATE TABLE ab_events (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
edge_id UUID NOT NULL,
|
|
article_id UUID NOT NULL,
|
|
collection_id UUID NOT NULL,
|
|
event_type VARCHAR(16) NOT NULL CHECK (event_type IN ('impression', 'click')),
|
|
-- Timens posisjon i uken (0-167) for tidspunkt-normalisering.
|
|
-- Mandag 00:00 = 0, søndag 23:00 = 167.
|
|
hour_of_week SMALLINT NOT NULL DEFAULT (
|
|
EXTRACT(ISODOW FROM now())::int * 24
|
|
- 24
|
|
+ EXTRACT(HOUR FROM now())::int
|
|
),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- Primær-oppslag: alle events for en bestemt edge
|
|
CREATE INDEX idx_ab_events_edge ON ab_events(edge_id, event_type);
|
|
|
|
-- Opprydning/aggregering per samling
|
|
CREATE INDEX idx_ab_events_collection ON ab_events(collection_id, created_at);
|
|
|
|
-- For periodisk evaluering: finn alle aktive tester per samling
|
|
CREATE INDEX idx_ab_events_article ON ab_events(article_id, edge_id);
|
|
|
|
COMMENT ON TABLE ab_events IS 'A/B-test impression/klikk-logg for presentasjonselement-varianter';
|
|
COMMENT ON COLUMN ab_events.hour_of_week IS 'Timens posisjon i uken (0-167) for CTR-normalisering mot tidspunkt-baseline';
|