Skip to content

chore(sc-46274): retire the legacy fallback, park the experiments framework (phase 3) - #3579

Open
dcschreiber wants to merge 5 commits into
masterfrom
chore/sc-46274/phase-3-remove-legacy-fallback
Open

chore(sc-46274): retire the legacy fallback, park the experiments framework (phase 3)#3579
dcschreiber wants to merge 5 commits into
masterfrom
chore/sc-46274/phase-3-remove-legacy-fallback

Conversation

@dcschreiber

@dcschreiber dcschreiber commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

(Claude writing on Daniel's behalf)

Replaces #3573. Per Akiva's review: the experiments framework stays in the codebase — model, admin tooling, and opt-in endpoint are all untouched and working, parked for a future experiment. Only the data goes.

Now based on master (was stacked on the phase-1 branch, which has since squash-merged) and rebased over #3584.

What this PR does, once the opt-out migration has run:

  • Removes the legacy fallback from sefaria.helper.library_assistant: a profile without settings.library_assistant now reads as off (the migration is re-runnable as a catch-up). The in_chatbot_experiment prop goes with it.
  • Restricts the Library Assistant promo banner to logged-out visitors — see the note below; this is the one behavioural change in the PR beyond the fallback removal.
  • Renames ChatbotExperimentBannerLibraryAssistantPromoBanner (dismissal storage key deliberately unchanged) and adds docs/decisions/library_assistant_naming.md recording the chatbot-vs-library_assistant naming line.
  • Rewords the TEMPORARY markers on the surviving experiments plumbing to "parked experiments framework" notes, since that code is no longer scheduled for removal.
  • Ships the phase-4 wipe script (scripts/migrations/wipe_experiments_data.py): archives every UserExperimentSettings row to db.experiments_data_archive, deletes the rows, and unsets profiles.experiments. It refuses to run while any profile lacks the setting key, because the migration reads its cohorts from the rows it deletes. Phase 4 is now that script run — no schema change, the table stays (empty).

The promo banner needed fixing, and it is fixed here

Removing in_chatbot_experiment left the banner gated on !chatbot_enabled — "show the promo to anyone who doesn't currently have the assistant." Before this phase, in_chatbot_experiment meant this user has made a choice about the assistant, whatever it was, so the promo skipped them.

Post-migration every profile carries an explicit settings.library_assistant, so the only logged-in users with the assistant off are the ones who deliberately turned it off. The new condition therefore aimed the "Enhance Your Learning Experience — Try our AI-powered Library Assistant" banner, with its Try It button, at precisely the people who had just said no — immediately, on the account settings page where they said it, overlaying the save controls.

The fix here gates the banner on !Sefaria._uid: it shows to logged-out visitors only. That matches its stated purpose as a "log in to try" acquisition funnel, and post-migration it is equivalent to "don't ask anyone who has already answered" — because after the flip, everyone logged in has answered.

Caught by LAS-060 in the opt-out browser suite (#3585), which asserts directly that a user who turned the assistant off is not asked to try it.

Follow-up worth a decision, not blocking: LibraryAssistantPromoBanner still carries a logged-in branch (the Try It button and its handleJoineditProfileAPI call, plus the chatbot_experiment_banner_dismissed cookie name). With this gate in place that branch is unreachable. It is left in deliberately rather than deleted in the same PR — but if we're confident the promo is logged-out-only for good, it should come out, so nobody re-arms this by relaxing the gate.

Verified

The opt-out browser suite from #3585 was merged into this branch locally and run against it, LA_PHASE=post, against http://localhost:8000 with a restored production Mongo dump and the cohorts seeded and migrated:

19/19 passed — the same 19 tests that pass at phase 1 pre-migration and phase 2 post-migration. Every assertion is phase-invariant except never_chose, whose answer the migration is supposed to change. That the suite passes identically on phases 2 and 3 is the evidence that removing the fallback is unobservable — a stronger statement than any phase-3-specific test.

Before the promo fix, the same run was 18/19, the single failure being LAS-060.

Not verified: nothing has been run on staging or a cauldron.

One precision note for whoever reads LAS-061 later: its comment explains that never_chose is the only cohort where the two suppression rules can disagree. With the promo now gated on logged-out-ness rather than on the setting, that reasoning no longer describes why the assertion holds post-migration — the test still passes, and still passes at pre against master, but its stated rationale is one phase out of date.

🤖 Generated with Claude Code

@gitvelocity-reviewer

gitvelocity-reviewer Bot commented Aug 4, 2026

Copy link
Copy Markdown

📊 Code Quality Score: 33/100

Base Score 55 × ESF 0.6 = 33

Category Score Factors
🔭 Scope 10/20 11 files across frontend JSX/JS, backend Python views/helper, tests, templates, and migration scripts; removes a cross-cutting feature flag system; no new public APIs
🏗️ Architecture 12/20 Removes two-rule fallback system simplifying architecture; eliminates cross-cutting dependency from reader.models into library_assistant.py; new migration script adds data lifecycle management; clean removal of circular-ish dependency
⚙️ Implementation 10/20 Core logic simplification (two-rule to one-rule); migration script has pre-flight checks, archiving, dry-run mode; JSX comment syntax bug (// inside JSX return) will cause build failure; banner visibility logic change is straightforward
⚠️ Risk 11/20 Removes fallback protecting unmigrated users (requires migration to have run first); rollback script now refuses to run narrowing recovery window; data deletion in wipe script is irreversible though archived; JSX syntax error risks build failure
✅ Quality 10/15 Tests updated to match new behavior with appropriate removals; good documentation in migration scripts with ordering requirements; JSX comment bug reduces quality; no new E2E tests but change is primarily a removal
🔒 Perf / Security 2/5 Removes user_has_experiments DB query from hot base_props path (minor perf improvement); archive-before-delete pattern in migration script

Was this score accurate? 👍 Yes · 👎 No

How this was scored →

Scored by GitVelocity · How are scores calculated?

dcschreiber and others added 5 commits August 6, 2026 08:11
…ramework

The framework itself (model, admin tooling, opt-in endpoint) stays in the
codebase, parked for a future experiment — but the assistant no longer reads
it: the legacy fallback for a missing settings key is gone (absent now reads
as off, pending a catch-up migration run), and the in_chatbot_experiment prop
went with it. TEMPORARY markers on the surviving plumbing become 'parked
experiments framework' notes, since the code is staying.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The banner promotes the product, not the retired experiment. The dismissal
storage key keeps its original name so nobody's dismissal history resets.
The show condition now keys on chatbot_enabled: with in_chatbot_experiment
gone, the banner shows whenever the assistant isn't running for the viewer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 4 of the opt-out rollout: the framework code stays parked, but the
data is not retained. Archives every UserExperimentSettings row to
db.experiments_data_archive, deletes the rows, and unsets the Mongo
profiles.experiments field. Refuses to run before the migration has given
every profile its own setting key, since the migration's cohorts come from
the rows this deletes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The banner's logged-in branch offered a "Try It" button gated on the assistant
being off. Once every profile carries an explicit setting, the only logged-in
users it reaches are the ones who deliberately turned the assistant off — so it
asked precisely the people who had said no, immediately, on the settings page
where they said it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dcschreiber
dcschreiber force-pushed the chore/sc-46274/phase-3-remove-legacy-fallback branch from ddd47d6 to 6e1da35 Compare August 6, 2026 05:13
@dcschreiber
dcschreiber changed the base branch from chore/sc-46272/phase-1-library-assistant-setting to master August 6, 2026 05:13
@dcschreiber
dcschreiber marked this pull request as draft August 6, 2026 10:01
@dcschreiber
dcschreiber marked this pull request as ready for review August 6, 2026 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant