Project: doctolib-doctolib · Branch: master · Mode: · Model: claude-haiku-4-5-20251001 Stats: 1 user messages, 29 tool calls, tools used: Bash, Grep, Read, mcp__excalidraw__read_me, mcp__excalidraw__create_view. Conversation Turn 1 — User Find where Rails serializes feature switches into frontend CONSTANTS (JavaScript). Specifically how the send_to_front: true flag in config/feature_switches.yml causes a feature switch like nhr_document_list to become NHR_DOCUMENT_LIST_ENABLED in the frontend CONSTANTS object. Look for: 1. Ruby code that reads config/feature_switches.yml and generates frontend constants 2. Where CONSTANTS is built/serialized in a view or serializer for the Rails app 3. How cohort-type feature switches with send_to_front: true are evaluated for the current account Key questions: - Does the Rails backend check the cohort at request time and set the constant, OR - Is the feature switch globally enabled in the dev environment somehow? - Is there a way to override feature switches locally in development that might cause nhr_document_list to be always true? Search in app/, engines/, lib/ directories for Ruby code related to feature switches and frontend constants serialization. Turn 1 — Assistant I'll help you find how Rails serializes feature switches into frontend CONSTANTS. Let me search for the relevant code. Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f -name "feature_switches.yml" | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/test/fixtures/files/application_preference/feature_switches.yml /Users/USER/workspace/doctolib/doctolib/config/feature_switches.yml /Users/USER/workspace/doctolib/doctolib/lib/data/organization/feature_switches.yml Now let me search for code that processes feature switches and sends them to the frontend: Tools used: - Grep: send_to_front|NHR_DOCUMENT_LIST_ENABLED|CONSTANTS.feature in /Users/USER/workspace/doctolib/doctolib Tool results: → result (ok): Found 9 files test/static_checks/feature_switches_test.rb test/services/countries/feature_test.rb app/services/countries/feature.rb engines/patient_mobile_app/test/controllers/patient_mobile_app/configuration_api/v1/configurations_controller_test.rb app/helpers/frontend_constants_helper.rb test/static_checks/country_feature_test.rb test/helpers/frontend_constants_helper_test.rb engines/feature_switches/test/helpers/feature_switches/feature_switches_helper_test.rb engines/feature_switches/app/hel …(truncated, 48 more chars) Perfect! Let me examine the key files: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/helpers/frontend_constants_helper.rb Tool results: → result (ok): 1→# frozen_string_literal: true 2→ 3→module FrontendConstantsHelper 4→ # rubocop:todo DoctolibInternal/NoCountrySpecificLogic 5→ CONSTANTS = { 6→ AGENDA_DEFAULT_MAX_TIME: Preferences::AccountPreferences::Api::DEFAULT_MAX_TIME, 7→ AGENDA_DEFAULT_MIN_TIME: Preferences::AccountPreferences::Api::DEFAULT_MIN_TIME, 8→ AMELI_WEB_SERVICE_URL: ENV.fetch('AMELI_WEB_SERVICE_URL', nil), 9→ APPOINTMENT_PAGINATION_SIZE: Appointment::PAGINATION_SIZE, 10 …(truncated, 18601 more chars) Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/engines/feature_switches/app/helpers/feature_switches/feature_switches_helper.rb Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/config/feature_switches.yml Tool results: → result (ERROR): File content (441.4KB) exceeds maximum allowed size (256KB). Use offset and limit parameters to read specific portions of the file, or search for specific content instead of reading the whole file. Tool results: → result (ok): 1→# frozen_string_literal: true 2→ 3→module FeatureSwitches::FeatureSwitchesHelper 4→ # rubocop:disable Metrics/MethodLength 5→ def list_feature_switches(context: {}, frontend_only: false) 6→ global_toggles = {} 7→ global_values = {} 8→ global_factors = {} 9→ 10→ country_toggles = {} 11→ country_values = {} 12→ country_factors = {} 13→ 14→ # We skip type requirements to ease migration pains. We cannot know ahead o …(truncated, 2837 more chars) Let me search for ApplicationPreference and the feature evaluation logic: Tools used: - Bash: grep -r "class ApplicationPreference" /Users/USER/workspace/doctolib/doctolib/app --include=".rb" | head -5 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/models/application_preference/evaluation.rb:class ApplicationPreference::Evaluation < Db4Record /Users/USER/workspace/doctolib/doctolib/app/models/application_preference/warn_expired_feature_switches.rb:class ApplicationPreference::WarnExpiredFeatureSwitches /Users/USER/workspace/doctolib/doctolib/app/models/application_preference/trim_feature_switch_entries.rb:class ApplicationPreference::TrimFeatureSwitchEntries /Users/USER/workspace/doctolib/doctoli …(truncated, 288 more chars) Now let me look at the ApplicationPreference model to understand how features are loaded and evaluated: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/models/application_preference.rb (1–200) Tool results: → result (ok): 1→# frozen_string_literal: true 2→ 3→class ApplicationPreference < Db1Record 4→ data_taxonomy do 5→ description('Application feature switches state') 6→ 7→ default( 8→ secret: false, 9→ system_id: false, 10→ health_information_likelihood: :none, 11→ data_subject_identity_likelihood: :none, 12→ data_subject_info_likelihood: :none, 13→ data_subjects: [:not_applicable], 14→ sensitive_likelihood: :n …(truncated, 8129 more chars) Tools used: - Bash: grep -n "FEATURES\|feature_enabled?" /Users/USER/workspace/doctolib/doctolib/app/models/application_preference.rb | head -30 Tool results: → result (ok): 31: GROUPED_FEATURES = 34: GROUPED_CIRCUIT_BREAKER_FEATURES = 39: FEATURES = 40: GROUPED_FEATURES 43: .merge!(GROUPED_CIRCUIT_BREAKER_FEATURES.map { |_, v| v['features'] }.reduce(:merge)) 46: COHORT_FEATURE_KEYS = ApplicationPreference::FEATURES.select { |_, metadata| metadata['cohort_types'].present? }.keys 54: store_accessor :features_enabled, FEATURES.keys, FEATURES.keys.map { |f| "#{f}_cohorts" } 75: :feature_enabled?, 168: FEATURES.each_key do |feature| 171: …(truncated, 1041 more chars) Let me look at the feature_enabled? method in detail: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/models/application_preference.rb (299–399) Tool results: → result (ok): 299→ def feature_enabled?(feature, context: nil) 300→ return evaluate_with_context(feature, context) if cohort_feature?(feature) 301→ return apply_factor?(feature) if factor_feature_switch?(feature) 302→ feature_value(feature).present? 303→ end 304→ 305→ def feature_enabled_for_country?(feature, country) 306→ raise 'Please use feature_enabled! method instead.' unless country_feature_switch?(feature) 307→ 308→ return apply_factor?(feature, country: cou …(truncated, 4417 more chars) Now let me search for evaluate_with_context and cohort evaluation: Tools used: - Bash: grep -n "evaluate_with_context\|cohort_feature?" /Users/USER/workspace/doctolib/doctolib/app/models/application_preference.rb | head -20 Tool results: → result (ok): 85: :cohort_feature?, 247: elsif cohort_feature?(feature) 300: return evaluate_with_context(feature, context) if cohort_feature?(feature) 470: def cohort_feature?(feature) 475: raise "Expected #{feature} to be a cohort feature but was not" unless cohort_feature?(feature) 517: raise "Expected #{feature} to be a cohort feature but was not" unless cohort_feature?(feature) 523: def evaluate_with_context(feature, context) Let me look at the evaluate_with_context method: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/models/application_preference.rb (523–573) Tool results: → result (ok): 523→ def evaluate_with_context(feature, context) 524→ context ||= {} if Stagery.stage.production? 525→ 526→ unless context.is_a?(Hash) 527→ raise "#{feature}: You must supply a context to evaluate this feature flag (received #{context.class})" 528→ end 529→ 530→ context[:cohorts] ||= {} 531→ 532→ required_types = cohort_types(feature) 533→ context_check_required_types!(feature, context, required_types) unless context[:skip_cohort_type_require …(truncated, 1843 more chars) Now let me search for the key place where nhr_document_list is checked - looking at the feature_switches.yml config: Tools used: - Bash: grep -A 5 -B 2 "nhr_document_list" /Users/USER/workspace/doctolib/doctolib/config/feature_switches.yml Tool results: → result (ok): team: FIRE value_in_test: false nhr_document_list: cohort_types: - account default: false details: Enables the NHR (National Health Records / DMP) document list modal for healthcare professionals. Part of DMP 3.1a certification. Let me check if nhr_document_list has send_to_front: Tools used: - Bash: grep -A 10 "nhr_document_list:" /Users/USER/workspace/doctolib/doctolib/config/feature_switches.yml Tool results: → result (ok): nhr_document_list: cohort_types: - account default: false details: Enables the NHR (National Health Records / DMP) document list modal for healthcare professionals. Part of DMP 3.1a certification. expire_at: 2027-06-01 message: NHR document list — DMP 3.1a feature rollout send_to_front: true team: FIRE value_in_test: false Perfect! Now let me look at how the cohort context is built in the frontend_constants_helper: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/helpers/frontend_constants_helper.rb (282–302) Tool results: → result (ok): 282→ def build_cohort_context 283→ resources = [] 284→ 285→ # Cohort feature switches will be active if the account or any organization is part of the cohort 286→ # They will also be active if the meta-cohort INCLUDE_ALL is included in the feature cohorts, 287→ # even outside of the pro domain. 288→ # To send organization-specific cohort feature flags to the front, evaluate them with a custom 289→ # context in your FrontendConstants, or as part of your Rea …(truncated, 1004 more chars) Now let me search for ApplicationPreferences::ContextResolution: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f -name ".rb" -path "/application_preferences" | grep -i "context_resolution\|context" Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/test/lib/application_preferences/context_resolution_test.rb /Users/USER/workspace/doctolib/doctolib/lib/application_preferences/context_resolution.rb Let me look at context resolution: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/lib/application_preferences/context_resolution.rb Tool results: → result (ok): 1→# frozen_string_literal: true 2→ 3→module ApplicationPreferences 4→ module ContextResolution 5→ RESOURCE_TYPE_MAP = { 6→ 'Account' => Cohorts::Resolution::RESOURCE_TYPES[:ACCOUNT], 7→ 'Authentication::AccountContext' => Cohorts::Resolution::RESOURCE_TYPES[:ACCOUNT], 8→ 'Legal::Account' => Cohorts::Resolution::RESOURCE_TYPES[:ACCOUNT], 9→ 'StaffAccounts::Account' => Cohorts::Resolution::RESOURCE_TYPES[:ACCOUNT], 10→ 'Teles …(truncated, 2963 more chars) Now let me check where the frontend constants are injected into views: Tools used: - Bash: grep -r "inject_constants" /Users/USER/workspace/doctolib/doctolib --include=".erb" | head -20 Tool results: → result (ok): (Bash completed with no output) Let me search for where inject_constants is used: Tools used: - Bash: grep -r "inject_constants" /Users/USER/workspace/doctolib/doctolib/app --include=".rb" | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/helpers/frontend_constants_helper.rb: def inject_constants Let me search in view files: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -name ".html" -o -name ".haml" | xargs grep -l "inject_constants" 2>/dev/null | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/views/configuration/telehealth/enroll.html+iframe.slim /Users/USER/workspace/doctolib/doctolib/app/views/secretary/front_desk/show.html.slim /Users/USER/workspace/doctolib/doctolib/app/views/layouts/configuration.html.slim /Users/USER/workspace/doctolib/doctolib/app/views/layouts/billing_mobile_offline.html.slim /Users/USER/workspace/doctolib/doctolib/app/views/layouts/pharmacy.html.slim /Users/USER/workspace/doctolib/doctolib/app/views/layouts/billeo. …(truncated, 1334 more chars) Let me look at one of these views: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/views/layouts/application.html.slim (1–100) Tool results: → result (ok): 1→- if Doctowebsite::Api.doctowebsite_access?(account_id: current_account_or_nil&.id) 2→ - content_for(:left_navigation_bar) do 3→ = react_component(React::FreemiumLeftNavigationBar, is_patient_website: true) 4→ 5→doctype html 6→/! 7→ Looking at our code ? 8→ Take a closer look – we offer rewards of up to €50,000 for impactful security bug discoveries. 9→ https://yeswehack.com/programs/doctolib-public-bug-bounty-program 10→ 11→html lang=I18n …(truncated, 5192 more chars) Perfect! Now let me look at how the feature switch evaluation checks for INCLUDE_ALL in development: Tools used: - Bash: grep -r "INCLUDE_ALL" /Users/USER/workspace/doctolib/doctolib/lib /Users/USER/workspace/doctolib/doctolib/app --include=".rb" | head -30 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/lib/tasks/billeo.rb: [ApplicationPreference::INCLUDE_ALL_COHORT_ID], /Users/USER/workspace/doctolib/doctolib/app/mailers/account_mailer.rb: deprecation__soft_deleted: HcpAccount::Api::Account::SOFT_DELETED__INCLUDE_ALL, /Users/USER/workspace/doctolib/doctolib/app/models/account.rb: deprecation__soft_deleted: HcpAccount::Api::Account::SOFT_DELETED__INCLUDE_ALL, /Users/USER/workspace/doctolib/doctolib/app/models/application_preference. …(truncated, 3323 more chars) Now let me look for where cohorts might be set or managed in development: Tools used: - Bash: find /Users/USER/workspace/doctolib/doctolib -type f -name ".rb" -path "/engines/cohorts" | head -20 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/engines/cohorts/app/models/cohorts/membership.rb /Users/USER/workspace/doctolib/doctolib/engines/cohorts/app/models/cohorts/history.rb /Users/USER/workspace/doctolib/doctolib/engines/cohorts/app/models/cohorts/csv.rb /Users/USER/workspace/doctolib/doctolib/engines/cohorts/app/models/cohorts/expired.rb /Users/USER/workspace/doctolib/doctolib/engines/cohorts/app/models/cohorts/resource.rb /Users/USER/workspace/doctolib/doctolib/engines/cohorts/app/models/coh …(truncated, 1353 more chars) Let me look at how cohorts are resolved and how it determines if an account is in a cohort: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/engines/cohorts/app/public/cohorts/resolution.rb (1–150) Tool results: → result (ok): 1→# frozen_string_literal: true 2→ 3→module Cohorts 4→ module Resolution 5→ RESOURCE_TYPES = Cohorts::Cohort.resource_types 6→ 7→ class << self 8→ def cohorts_from_identities(identities) 9→ Cohort::Resolution.from_identities(identities) 10→ end 11→ 12→ Doctolib::O11y.tracer.add_method_tracer self, :cohorts_from_identities 13→ 14→ def cohorts_from_identity(identity) 15→ # uncached; used in adm …(truncated, 922 more chars) Now let me look at the test file to see if there's any special dev setup: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/test/helpers/frontend_constants_helper_test.rb (1–200) Tool results: → result (ok): 1→# frozen_string_literal: true 2→ 3→require 'test_helper' 4→ 5→class FrontendConstantsHelperTest < Doctolib::Testing::ActionView::TestCase 6→ include AppointmentsHelper 7→ include ConfigurationHelper 8→ include Cohorts::CohortUtilsTestHelper 9→ include Domain 10→ 11→ before do 12→ stubs(:country).returns(Country::FR) 13→ @test_current_account = nil 14→ end 15→ 16→ def current_account_or_nil 17→ @test_current …(truncated, 8694 more chars) Perfect! Now let me search for local dev overrides or special development mode handling: Tools used: - Bash: grep -r "development\|local" /Users/USER/workspace/doctolib/doctolib/app/models/application_preference.rb | head -20 Tool results: → result (ok): (Bash completed with no output) Let me check the view for where assume_or_current_account comes from and if there's a way it bypasses the cohort check in dev: Tools used: - Bash: grep -r "desktop_pro_or_mobile_pro_domain?" /Users/USER/workspace/doctolib/doctolib/app --include=".rb" -A 5 | head -50 Tool results: → result (ok): /Users/USER/workspace/doctolib/doctolib/app/controllers/application_controller.rb: :desktop_pro_or_mobile_pro_domain?, /Users/USER/workspace/doctolib/doctolib/app/controllers/application_controller.rb- :mobile_version?, /Users/USER/workspace/doctolib/doctolib/app/controllers/application_controller.rb- :tanker_fields, /Users/USER/workspace/doctolib/doctolib/app/controllers/application_controller.rb- :show_pin_set?, /Users/USER/workspace/ …(truncated, 4770 more chars) Let me look at the domain concern: Tools used: - Read: /Users/USER/workspace/doctolib/doctolib/app/controllers/concerns/domain.rb Tool results: → result (ok): 1→# typed: true 2→# frozen_string_literal: true 3→ 4→module Domain 5→ extend ActiveSupport::Concern 6→ extend T::Sig 7→ 8→ # TODO(i18n): This should come from somewhere within the Country config 9→ # rubocop:todo DoctolibInternal/NoCountrySpecificLogic 10→ TLD_DOMAIN_ENV_MAP = { 11→ 'fr' => { 12→ 'www' => 'WWW_DOMAIN', 13→ 'pro' => 'PRO_DOMAIN', 14→ 'admin' => 'ADMIN_DOMAIN', 15→ 'mobile' => 'MOBILE_DOMAI …(truncated, 9631 more chars) Now let me create a comprehensive diagram showing the flow. First, let me check the mcp__excalidraw tools: Tools used: - mcp__excalidraw__read_me (inputs: ) Tool results: → result (ok): # Excalidraw Element Format Thanks for calling read_me! Do NOT call it again in this conversation — you will not see anything new. Now use create_view to draw. Color Palette (use consistently across all tools) Primary Colors | Name | Hex | Use | |------|-----|-----| | Blue | #4a9eed | Primary actions, links, data series 1 | | Amber | #f59e0b | Warnings, highlights, data series 2 | | Green | #22c55e | Success, positive, data series 3 | | Red | #ef4444 | Errors, negative, data se …(truncated, 26442 more chars) Now let me create a comprehensive diagram showing the feature switch serialization flow: Tools used: - mcp__excalidraw__create_view (inputs: elements) Tool results: → result (ok): {"checkpointId":"844105470d184a37a9"} Perfect! Now let me create a detailed summary document as a response: Summary: How Rails Serializes Feature Switches to Frontend CONSTANTS I've traced the complete flow of how feature switches like nhr_document_list become NHR_DOCUMENT_LIST_ENABLED in the frontend CONSTANTS. Here's what I found: Key Files Involved 1. Configuration: /Users/USER/workspace/doctolib/doctolib/config/feature_switches.yml - Defines all feature switches with metadata including send_to_front: true flag - nhr_document_list has send_to_front: true and cohort_types: [account] 2. Primary Helper: /Users/USER/workspace/doctolib/doctolib/app/helpers/frontend_constants_helper.rb - inject_constants() - Called in views (e.g., /app/views/layouts/application.html.slim line 56) - build_constants() - Merges static CONSTANTS with feature switches and dynamic values - feature_switches_sent_to_front() - Filters features where send_to_front == true - build_cohort_context() - Resolves cohort membership at request time - evaluate_feature_switch_pair() - Converts feature name to constant name (e.g., nhr_document_list → NHR_DOCUMENT_LIST_ENABLED) 3. Feature Model: /Users/USER/workspace/doctolib/doctolib/app/models/application_preference.rb - FEATURES - Loaded from feature_switches.yml on boot - feature_enabled?(feature, context:) - Evaluates feature with cohort context - evaluate_with_context(feature, context) - Core cohort evaluation logic (line 523-545) - cohort_feature?(feature) - Determines if feature requires cohort evaluation 4. Cohort Resolution: /Users/USER/workspace/doctolib/doctolib/lib/application_preferences/context_resolution.rb - resolved_cohorts_from_resources(resources) - Maps account/org to cohorts they belong to - evaluation_context() - Returns hash with cohort memberships for evaluation The Flow: Request Time Evaluation Here's how nhr_document_list becomes NHR_DOCUMENT_LIST_ENABLED: Step 1: View Renders Constants (Request Time) View (layout) → calls inject_constants helper → Generates: window.dl_constants = {build_constants().to_json} → Executes BEFORE page load in browser Step 2: Build Constants Dictionary frontend_constants_helper.rb lines 120-129 build_constants returns: { CONSTANTS (static), built_with_account: account.id, engines_frontend_constants, feature_switches_sent_to_front, # ← FEATURE SWITCHES EVALUATED HERE dynamic_constants, country_features, deprecated_associated_account_fs } Step 3: Filter and Evaluate Cohort Features frontend_constants_helper.rb lines 133-140 feature_switches_sent_to_front: 1. Filters ApplicationPreference::FEATURES for send_to_front == true 2. Builds cohort_context via build_cohort_context() 3. For each feature, calls evaluate_feature_switch_pair(feature_name, feature_attributes, cohort_context) Step 4: Build Cohort Context frontend_constants_helper.rb lines 282-296 build_cohort_context: IF: - assumed_or_current_account.present? (user is logged in) - desktop_pro_or_mobile_pro_domain? (pro or mobile-pro domain) THEN: - Resources = [account, account.all_current_organizations] - Resolve cohorts from these resources - Return evaluation_context with cohort mappings ELSE: - Return empty resources (INCLUDE_ALL still works) Step 5: Evaluate Feature Switch Pair frontend_constants_helper.rb lines 219-250 evaluate_feature_switch_pair(feature_name, feature_attributes, cohort_context): 1. Checks if per_country, per_speciality, per_ssid flags 2. For bare toggle (like nhr_document_list): - Calls: ApplicationPreference.nhr_document_list_enabled?(context: cohort_context) 3. Converts feature_name to CONSTANT: - "nhr_document_list" → "NHR_DOCUMENT_LIST_ENABLED" 4. Returns [constant_name, boolean_value] Step 6: Cohort Evaluation at Feature Level application_preference.rb lines 299-303 feature_enabled?(feature, context: nil): IF cohort_feature?(feature): return evaluate_with_context(feature, context) ELSIF factor_feature_switch?: return apply_factor?(feature) ELSE: return feature_value(feature).present? Step 7: Core Cohort Evaluation application_preference.rb lines 523-545 evaluate_with_context(feature, context): 1. Context contains cohort_id lists for account/org 2. Get active_cohorts for the feature from database 3. RETURNS TRUE if: a) active_cohorts includes INCLUDE_ALL_COHORT_ID b) active_cohorts intersects with context[:cohorts][:account] or context[:cohorts][:organization] 4. RETURNS FALSE otherwise Key Questions Answered Q: Does the backend check the cohort at request time? A: YES. The cohort evaluation happens synchronously during view rendering, not on the frontend. The context is built with build_cohort_context(), which resolves actual cohort memberships for the current account. Q: Is the feature switch globally enabled in dev? A: NO. Feature switches are evaluated per-request based on: - Whether the account is in the feature's assigned cohorts - OR whether the feature has the meta-cohort INCLUDE_ALL_COHORT_ID Q: Is there a way to override locally in development? A: YES, multiple ways: 1. Database: ApplicationPreference.enable_feature!(:nhr_document_list) - enables globally 2. Cohorts: Add account/org to the cohort assigned to the feature 3. INCLUDE_ALL: Add 'INCLUDE_ALL' cohort ID to nhr_document_list feature cohorts 4. Direct assignment: Manually call ApplicationPreference.update_cohorts!(:nhr_document_list, [cohort_id]) Domain Dependency The cohort context is ONLY built if BOTH conditions are met: if assumed_or_current_account.present? && desktop_pro_or_mobile_pro_domain? This means: - On PRO domain (ENV['PRO_DOMAIN']) - cohort context is built - On MOBILE-PRO domain (ENV['PRO_MOBILE_SUBDOMAIN']) - cohort context is built - On WWW domain - cohort features evaluate to FALSE (empty resources) - No logged-in account - cohort features evaluate to FALSE File Locations (Absolute Paths) - /Users/USER/workspace/doctolib/doctolib/app/helpers/frontend_constants_helper.rb - Main serialization logic - /Users/USER/workspace/doctolib/doctolib/app/models/application_preference.rb - Feature evaluation - /Users/USER/workspace/doctolib/doctolib/lib/application_preferences/context_resolution.rb - Cohort resolution - /Users/USER/workspace/doctolib/doctolib/config/feature_switches.yml - Feature definitions - /Users/USER/workspace/doctolib/doctolib/engines/cohorts/ - Cohort engine (manages membership) - /Users/USER/workspace/doctolib/doctolib/app/views/layouts/application.html.slim - View calling inject_constants