Add merge_requests_risk_assessments and risk_outcomes tables
What does this MR do and why?
Adds the data model backing merge request risk classification: merge_requests_risk_assessments holds the risk score, confidence, scoring function version, signal breakdown, missing signals, domain tags, and raw classification payload for a merge request. merge_requests_risk_outcomes records calibration signals against an assessment.
The outcomes table isn't consumed by anything yet - calibration work lands from Phase 3 onward - but it's added now so RiskAssessment can declare the association once the model exists. Each table's project_id foreign key is added in its own migration so only one table is locked at a time.
This is a scoped extraction of the data-model piece from the feature/mr-risk-classification spike branch. It intentionally excludes merge_requests_risk_overrides and its FK migrations - override storage belongs to Phase 6, not this one.
References
Part of &23131 (Phase 1)
Resolves #609289 (closed)
Screenshots or screen recordings
Not applicable - no UI changes.
How to set up and validate locally
- Pull this branch and run
bundle exec rails db:migrate. - Confirm both tables exist:
ActiveRecord::Base.connection.table_exists?(:merge_requests_risk_assessments) # => true ActiveRecord::Base.connection.table_exists?(:merge_requests_risk_outcomes) # => true - Run
bundle exec rails db:migrate:down VERSION=20260817203100(and the other three, in reverse order) to confirm the migrations roll back cleanly. - Run the migration specs:
bundle exec rspec spec/migrations/20260730120001_create_merge_requests_risk_assessments_spec.rb \ spec/migrations/20260730120002_add_project_fk_to_merge_requests_risk_assessments_spec.rb \ spec/migrations/20260730120003_create_merge_requests_risk_outcomes_spec.rb \ spec/migrations/20260730120004_add_project_fk_to_merge_requests_risk_outcomes_spec.rb - Run
bundle exec rspec spec/db/docs_spec.rb spec/db/schema_spec.rbto confirm thedb/docsentries anddb/structure.sqlare consistent.
Database growth, retention, and access patterns
Rollout scope
An assessment row is created for every eligible merge request, not only for projects with Duo Code Review enabled. "Eligible" means: the duo_mr_risk_classification feature flag is enabled, the project's root namespace is on an Ultimate (or trial) plan with an active Duo Enterprise add-on, and the risk_classification/v1 foundational flow is enabled for the project. Draft MRs are skipped and picked up once they leave draft state. Classification runs once per MR - at open or ready-for-review time, not on every push. See &23131 for Phase 1 gating logic, which lands in a later MR.
merge_requests_risk_assessments
- Retention:
user_lifecycle- rows follow the parent MR/project lifecycle with no independent expiry. Merge requests are effectively never deleted, so growth is indefinite in practice. - Growth driver: per-merge-request - one row per eligible MR (see Rollout scope above).
- Anticipated growth:
- 3 months: TODO rows/day, TODO cumulative rows
- 6 months: TODO rows/day, TODO cumulative rows
- 12 months: TODO rows/day, TODO cumulative rows
- Assumptions: TODO - based on GitLab.com's daily MR volume on Ultimate-plan namespaces with an active Duo Enterprise add-on, scaled by an assumed feature-flag rollout percentage at each milestone.
- Reads/writes:
- Writes: Two per assessed MR - one
INSERT(status: pending) when classification starts, and oneUPDATE(status: completed) when it finishes. On manual re-run, an existing assessment is left alone rather than overwritten, keeping writes at two per MR in the normal case. - Reads: Driven by MR risk widget queries (at least once per page view). No measured rate yet; the widget ships in a later MR.
- Row updates: occur exactly once, on the pending-to-completed transition.
- Writes: Two per assessed MR - one
merge_requests_risk_outcomes
- Retention:
user_lifecycle, same reasoning as above. - Growth driver: per-outcome-signal-observed (for example, a revert or hotfix detected against a scored MR) - not one-to-one with assessments.
- Anticipated growth: Zero rows for the foreseeable future. Nothing writes to this table yet; it's added now so
RiskAssessmentcan declare the association once the model exists. The write path lands in Phase 3 (calibration work), per &23131. - Reads/writes: None until Phase 3.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.