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_clientcampaigns_service←*_campaign*,*_ad_creatives,run_campaign_optimizationsequences_service←*_email_sequence*,*_sequence*,enroll_in_sequence,trigger_sequence_processingoffers_service←*_offer*,claim_offer,increment_offer_redemptionwebsite_builder←generate_website*,regenerate_*,update_page*,update_website*,save_website*,publish_websitedomains_service←purchase_domain*,verify_domain,configure_domain*,search_domains,get_domain*,get_purchased_domains,check_domain*,request_domain_verification*public_booking_service←create_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
Recommended sequencing
- Now (low risk, immediate): Bucket 2 — retire 17 HTTP duplicates + test variants after verification. Saves ~$2-5/mo + cleans namespace.
- 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.
- After basishybrid batching lands: Bucket 5 individual review — decide which clinical/chat/utility functions are truly dead.
- 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_instanceson terra-service or payment — webhook timeout cascade risk would amplify cost, not reduce it. - Touching anything in Bucket 1 — those are confirmed active.