Exposing past feed experiments in /admin/abtests (#17818)

Prior to this commit, as a matter of undocumented practice, we would
overwrite past experiments with upcoming experiments.

With this commit, we're leveraging a feature of the field_test gem:
declaring a winner.  Instead of overwriting an experiment with the next
experiment, we're going to declare the expiring experiment's winner then
prepend to the ./config/field_test.yml the new experiment.

The [field_test/app/views/field_test/experiments/index.html.erb][1] then
uses logic to first render "active" experiments and "completed"
experiments.  A "completed" experiment is one in which we've declared a
winner.

Closes forem/forem#17816

[1]:https://github.com/ankane/field_test/blob/master/app/views/field_test/experiments/index.html.erb
This commit is contained in:
Jeremy Friesen 2022-06-02 20:41:31 -04:00 committed by GitHub
parent 103394d5ad
commit 8fb98b9f30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 5 deletions

View file

@ -14,8 +14,10 @@ class AbExperiment < SimpleDelegator
# @see ./config/feed-variants/README.md
ORIGINAL_VARIANT = "original".freeze
CURRENT_FEED_STRATEGY_EXPERIMENT = FieldTest.config["experiments"]&.keys
&.detect { |e| e.start_with? "feed_strategy" }.freeze
# @note a present assumption is that we will have a feed_strategy oriented experiment.
CURRENT_FEED_STRATEGY_EXPERIMENT = FieldTest.config["experiments"].select do |key, value|
key.start_with?("feed_strategy") && !value["winner"]
end.keys.first
# Sometimes we might want to repurpose the same AbExperiment logic
# for different experiments. This provides the tooling for that

View file

@ -26,9 +26,77 @@ experiments:
- user_views_pages_on_at_least_nine_different_days_within_two_weeks
- user_publishes_post_at_least_two_times_within_week
- user_publishes_post_at_least_two_times_within_two_weeks
exclude:
bots: true
feed_strategy_starting_20220518:
winner: 20220518-variant
# NOTE: Required as we want only want to consider for conversion events that
# occurred on or after the given start_date.
start_date: 2022-05-09
variants:
- 20220422-variant
- 20220518-variant
weights:
- 80
- 20
goals:
- user_creates_pageview
- user_creates_article_reaction
- user_creates_comment
- user_publishes_post
- user_views_pages_on_at_least_four_different_days_within_a_week
- user_creates_article_reaction_on_four_different_days_within_a_week
- user_creates_comment_on_at_least_four_different_days_within_a_week
- user_publishes_post_on_four_different_days_within_a_week
# These are historical and may be userful
- user_views_pages_on_at_least_four_different_hours_within_a_day
- user_views_pages_on_at_least_twelve_different_hours_within_five_days
- user_views_pages_on_at_least_nine_different_days_within_two_weeks
- user_publishes_post_at_least_two_times_within_week
feed_strategy_starting_20220509:
winner: 20220422-variant
# NOTE: Required as we want only want to consider for conversion events that
# occurred on or after the given start_date.
start_date: 2022-05-09
variants:
- 20220422-variant
- 20220509-variant
weights:
- 80
- 20
goals:
- user_creates_pageview
- user_creates_article_reaction
- user_creates_comment
- user_publishes_post
- user_views_pages_on_at_least_four_different_days_within_a_week
- user_creates_article_reaction_on_four_different_days_within_a_week
- user_creates_comment_on_at_least_four_different_days_within_a_week
- user_publishes_post_on_four_different_days_within_a_week
# These are historical and may be userful
- user_views_pages_on_at_least_four_different_hours_within_a_day
- user_views_pages_on_at_least_twelve_different_hours_within_five_days
- user_views_pages_on_at_least_nine_different_days_within_two_weeks
- user_publishes_post_at_least_two_times_within_week
feed_strategy_starting_20220422:
winner: 20220422-variant
# NOTE: Required as we want only want to consider for conversion events that
# occurred on or after the given start_date.
start_date: 2022-04-22
variants:
- 20220415-incumbent
- 20220422-jennie-variant
weights:
- 80
- 20
goals:
- user_creates_comment
- user_creates_comment_on_at_least_four_different_days_within_a_week
- user_views_pages_on_at_least_four_different_days_within_a_week
- user_views_pages_on_at_least_four_different_hours_within_a_day
- user_views_pages_on_at_least_nine_different_days_within_two_weeks
- user_views_pages_on_at_least_twelve_different_hours_within_five_days
- user_publishes_post
- user_publishes_post_at_least_two_times_within_week
- user_publishes_post_at_least_two_times_within_two_weeks
# Dashboard performance
cache: true
precision: 2

View file

@ -4,6 +4,27 @@ RSpec.describe AbExperiment do
let(:controller) { ApplicationController.new }
let(:user) { double }
describe "CURRENT_FEED_STRATEGY_EXPERIMENT" do
subject(:variant) { described_class::CURRENT_FEED_STRATEGY_EXPERIMENT }
it { is_expected.to be_a String }
it "is a key in the FieldTest.config['experiments']" do
expect(FieldTest.config["experiments"].keys).to include(variant)
end
end
describe "validate field test experiment configuration" do
it "only allow at most one active feed_strategy (e.g. an experiment without a winner)" do
field_tests = Psych.load(Rails.root.join("config/field_test.yml").read)
active_field_tests = field_tests.fetch("experiments", {})
.select { |key, values| key.start_with?("feed_strategy") && !values["winner"] }
# We are only going to allow
expect(active_field_tests.size).to be <= 1
end
end
describe ".register_conversions_for" do
it "forwards delegates to Converter.call" do
allow(described_class::GoalConversionHandler).to receive(:call)