Skip to main content
Synced from the repo — do not edit here

Canonical source: docs/cloud-functions-retirement-plan-2026-05-29.md. This page is generated by docs/scripts/sync-handbook.mjs. Edit the source file in the repo; changes appear here on the next build.

Cloud Functions retirement plan — 2026-05-29

Context: 290 functions deployed in basis-hybrid, 251 had zero HTTP traffic in last 7 days. Plan is to retire what's truly unused without breaking scheduled/triggered/integration paths.

Honest savings expectation: dormant functions cost almost nothing in compute (no requests = no compute charge). Main wins from retirement = Artifact Registry storage + namespace hygiene + lower risk of accidental re-invocation of stale code. Probably $5-15/mo in pure compute savings, more in cognitive load. Real cost lever is still basishybrid batching (in flight) + lever #2 (conflict-check rewrite).

Bucket 1 — KEEP, do not touch (97 functions)

Running via cron scheduler (12 — they show 0 HTTP traffic but DO run)

aggregate_clinic_databases   heartbeat_dispatcher    mirror_recent_labs
process_waitlist_notifications rollup_call_analytics
backgroundrequesttask chat_unread_counter index_user_note
on_client_created on_lab_created onboarding_user_created_v1
processTerraWebhook

External webhooks / OAuth (15)

Anything ending in _webhook or _oauth_callback, plus sentry_webhook, mailersend_webhook. These sit idle until an external service calls; absence of recent traffic doesn't mean dead.

AI / copilot / labs / documents (26) — per user direction

analyze_document_summary_v2   analyze_lab   analyze_lab_report
atlas_api atlas_consumer
copilot_index_backfill copilot_index_backfill_clinic copilot_search
detect_clinic_personas extract_document_text extract_lab_text_from_pdf
get_lab_analysis_status get_lab_registry get_lab_registry_call
import_lab_values index_patient_data mcp_server
note_improve rag_query scribe_live_categorize
scribe_process_recording scribe_schedule_bot scribe_webhook
upsert_clinic_lab_synonyms vertex

Partner integrations (44) — DoseSpot, Fullscript, Junction, Google, Zoom

All dosespot_*, fullscript_*, junction_*, google_*, zoom_* functions. They look dormant because users haven't recently exercised those features; the moment one does they need to be live.


Bucket 2 — RETIRE NOW (17 functions, low risk)

HTTP duplicates of triggered functions (14)

These are HTTP variants that duplicate Firestore/Pub-Sub triggered counterparts. Likely artifacts from before the migration to triggered functions. Before retiring, verify no frontend code path calls them directly:

analyze_document_summary_http
analyze_document_summary_http_v2
chat_derive_http
chat_index_http
chat_notify_http
check_domain_verification_status_http
copilot_index_backfill_clinic_http
copilot_index_backfill_http
get_analytics_members_http
get_analytics_revenue_http
get_analytics_sessions_http
request_domain_verification_http
request_lab_support_http
save_branded_email_config_http
send_brand_test_email_http

Verification:

# For each, grep the three client codebases:
grep -rn '<function_name>' /Users/G/basis/hybrid/basisflow-web/{app,components,lib} \
/Users/G/basis/hybrid/basisweb/{app,components,lib} \
/Users/G/basis/hybrid/basishybrid/lib 2>/dev/null | grep -v ".next" | grep -v ".dart_tool"

If zero hits → safe to delete.

Test environment variants (3)

stripe_general_webhook_test
stripe_oauth_callback_test
stripe_webhook_test

Pretty sure these are staging environment leftovers. Confirm with firebase.json and *.env* files first — if no test env actively points at them, retire.


Bucket 3 — VERIFY THEN RETIRE — Backfills (16 functions)

User-specific direction: confirm none are used in automated backfilling from syncing before retiring.

backfill_charge_summary           # one-off?
backfill_clinic_document_copies # one-off?
backfill_core_monthly # might be SCHEDULED — verify
backfill_core_weekly # might be SCHEDULED — verify
backfill_document_links # one-off?
backfill_hdl_ratio_mismap # one-off (specific data fix)
backfill_lab_extraction # one-off?
backfill_labs_mirror # check vs labs_mirror schedule
backfill_labs_reclassify # one-off?
backfill_labs_series # one-off?
backfill_slack_history # one-off?
copilot_index_backfill # admin-trigger (KEEP)
copilot_index_backfill_clinic # admin-trigger (KEEP)
mirror_backfill # callable — admin tool, used during sync issues
mirror_backfill_admin # admin tool
retype_user_docs # one-off data fix

Verification pattern for each:

# Check for callers in backend
grep -rn '<backfill_name>' /Users/G/basis/basis-functions/functions/src 2>/dev/null

# Check for schedule decorator
grep -n '<backfill_name>' /Users/G/basis/basis-functions/functions/src/*.py | xargs grep -l 'on_schedule'

If function is called by NOTHING and has NO schedule → retire.


Bucket 4 — CONSOLIDATE — Growth (68 functions)

Big architectural opportunity. The growth subsystem has ~68 dormant + ~10 active functions, all small, mostly user-action-triggered, currently fragmented across many separate Cloud Functions.

Pattern: each does a small bit of work — create_lead / update_lead / get_lead / get_leads / convert_lead / update_lead_status — that could collapse into one growth_service callable with a request_type dispatcher (same pattern as clinic_service).

Suggested groupings for consolidation:

  • crm_service ← all *_lead*, convert_lead_to_client
  • campaigns_service*_campaign*, *_ad_creatives, run_campaign_optimization
  • sequences_service*_email_sequence*, *_sequence*, enroll_in_sequence, trigger_sequence_processing
  • offers_service*_offer*, claim_offer, increment_offer_redemption
  • website_buildergenerate_website*, regenerate_*, update_page*, update_website*, save_website*, publish_website
  • domains_servicepurchase_domain*, verify_domain, configure_domain*, search_domains, get_domain*, get_purchased_domains, check_domain*, request_domain_verification*
  • public_booking_servicecreate_public_booking, get_public_booking*

This is a real engineering project, not a delete-tonight task. Maybe 2-3 days of work to merge endpoints, update frontend callers, deploy, test, retire originals. Defer until basishybrid batching results land and we decide if growth perf actually matters right now.


Bucket 5 — INDIVIDUAL REVIEW (65 functions)

These need a closer look — could be legitimately active (Firestore triggers, internal callers, etc.) or genuinely dead. Do not retire en masse. Producing this list for you to skim:

Likely retire after verification

analyze_bug, log_bug        # debug/diagnostic utilities
analyze_import_csv # one-off?
chat_admin_set_flags # admin-only chat tool
chat_derive, chat_index, chat_notify # chat backend — verify triggers
clinical_agent_stream, clinical_assistant, clinical_quick, clinical_stream
# legacy clinical AI, likely superseded by atlas_api
heartbeat_worker # partner of heartbeat_dispatcher (which IS scheduled). Likely needed.
query_duckdb, sync_firestore_to_duckdb # analytics — verify if still used
terrawebhooktask # Cloud Tasks handler — almost certainly keep
summary_note_mirror_handler # Firestore trigger — keep

Likely KEEP (user-facing or integration)

booking_confirm, create_public_booking, get_public_booking_*, public_booking_*
# public booking flow — verify
call_center_* # planned feature (per memory)
configure_webhooks # admin tool
create_atlas_api_key # atlas API mgmt
create_custom_status, get_custom_statuses # custom statuses feature
delete_copilot_session, delete_document # cleanup actions
directory_sync # directory feature
get_ai_usage # AI billing/usage display
get_analytics_* # analytics endpoints (HTTP variants retired separately)
get_communications, add_communication # comms feature
get_default_payment_method # billing
get_website # growth/website
import_clients_csv, list_imports, check_import_conflicts # CSV import
join_clinic, leave_clinic # clinic membership
meal_service # meals feature
onboarding_form, onboarding_request_link, onboarding_service # onboarding
remove_addon_from_subscription, add_addon_to_subscription # billing
request_lab_support # lab support flow
resolve_clinic_by_code # clinic resolution
run_billing_maintenance # billing maintenance
search_providers # MDI provider search
send_auth_email # auth flow
set_custom_billing # billing
share_document_link # document sharing
slack_command, slack_events # slack integration
stripe_success # Stripe return URL
supplement_get_details, supplement_suggest # supplements (Fullscript integration)
update_billing_email, update_telehealth_config # config updates
activity_log_service # activity log
cleanup_clinic_permissions, cleanup_user_permissions # cleanup jobs
clinic_coach_notification_handler, coach_notification_handler # notifications
promote_pending_field # admin tool

  1. Now (low risk, immediate): Bucket 2 — retire 17 HTTP duplicates + test variants after verification. Saves ~$2-5/mo + cleans namespace.
  2. This week: Bucket 3 — backfill audit. Spend ~30 min per function checking callers. Retire the verified-orphan ones. Saves another ~$2-5/mo + much cleaner ops.
  3. After basishybrid batching lands: Bucket 5 individual review — decide which clinical/chat/utility functions are truly dead.
  4. Bigger project (deferred): Bucket 4 — growth consolidation. Real engineering effort.

What I'm NOT recommending

  • Bulk delete by no-traffic metric — too many false positives (scheduled, triggered, integration-idle).
  • Touching min_instances on terra-service or payment — webhook timeout cascade risk would amplify cost, not reduce it.
  • Touching anything in Bucket 1 — those are confirmed active.