-- +goose Up -- teaching_signal_aggregates holds the folded reviewer craft counts that feed the curation pipeline (WS8). -- Each row is one craft pattern, at one similarity band, for one decision outcome, on one engine model -- version, over one observation window, with the observation and success counts that generalize the -- reviewers' work. It carries NO PII, no candidate id, and no raw score, only the contents free counts from -- the scrub.TeachingSignal vocabulary. tenant_id is set for the live in tenant rows the producer writes -- (dp_applied false); the flag on cross tenant path later writes tenant_id NULL, dp_applied true rows after -- the differential privacy step. Global reference data: migrator owned, app SELECT only, outside RLS. The -- unique index keys on coalesce(tenant_id, the nil uuid) so the in tenant and cross tenant rows share one -- key space, and it includes model_version so a forked engine version is visible as a distinct row rather -- than silently overwriting a prior version's aggregate. CREATE TABLE teaching_signal_aggregates ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id uuid, -- set for live in tenant rows, NULL for cross tenant post DP rows dp_applied boolean NOT NULL DEFAULT false, pattern text NOT NULL, band text NOT NULL, outcome text NOT NULL, model_version text NOT NULL, observations int NOT NULL, successes int NOT NULL, window_start date NOT NULL, window_end date NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT teaching_signal_aggregates_counts_valid CHECK (successes >= 0 AND observations >= successes) ); -- One aggregate per tenant (or the nil uuid for the cross tenant cohort), pattern, band, outcome, model -- version, and window. coalesce maps a NULL tenant_id onto a fixed nil uuid so the cross tenant rows have a -- stable key; model_version in the key makes a forked version visible instead of silent. CREATE UNIQUE INDEX teaching_signal_aggregates_key ON teaching_signal_aggregates ( coalesce(tenant_id, '00000000-0000-0000-0000-000000000000'::uuid), pattern, band, outcome, model_version, window_start ); GRANT SELECT ON teaching_signal_aggregates TO missionmatch_app; -- +goose Down DROP TABLE IF EXISTS teaching_signal_aggregates;