Reader: future engineers and agents selecting the next legacy-web extraction seam. After reading, they should be able to choose the next wrapper group to extract without using ignored planning artifacts.
This inventory names the remaining responsibilities still owned by the legacy Flask runtime module and separates them from service boundaries that already moved out. It is grounded in tracked legacy-web source modules, route wrappers, focused services, and verifier scripts.
The document intentionally lists module and function names only. It does not include auth headers, API tokens, draft bodies, transcript contents, audio contents, or provider payload bodies.
gb_tts_app.py remains only a compatibility alias for older imports and tests that still need the historical module name. It is not a deployment entrypoint and is not a new import target for internal source.
Internal legacy-web source should import focused src.services.* modules or focused route dependency providers. After M013, app startup, job storage, TTS, STT, voice-clone, settings, categories, Soundboard, and legacy compatibility routes are off legacy_runtime_adapter; the adapter remains only as a transitional service module with no production route imports.
S04 complete: legacy_runtime.py is retired to an import-compatible shim for runtime construction ownership. Runtime globals are owned by explicit bootstrap/runtime services through legacy_runtime_bootstrap_service; no import-time Flask app, storage provider, connection-pool, ffmpeg/STT capability, cache/job/regen, upload limiter, or auth-bootstrap construction remains directly owned by legacy_runtime.py.
legacy_runtime.py for runtime construction; historical route-facing business wrappers continue to be tracked by focused S01/S02/S03 verifier seams until their remaining compatibility bodies are retired.gb_tts_app.py remains only a compatibility alias; its CLI path imports the legacy runtime module object rather than direct runtime symbols.src.app.create_app() owns Flask app construction through explicit bootstrap/runtime services by returning the bootstrap-owned app through page_bootstrap_service.register_legacy_blueprints.cache_runtime_service and persistent_job_service.category_runtime_service, draft_service, and pronunciation_service.S04 owns construction retirement after S03; do not re-expand cache/job/category/draft/pronunciation wrappers while addressing remaining compatibility names. The historical runtime globals import surface remains documented here as runtime globals compatibility scope, but construction ownership is explicit-service owned.
S03 complete: cache/job and category/draft/pronunciation compatibility groups are thinned. S04 owns runtime-global/final-shim retirement while preserving historical import names.
page_bootstrap_service owns Flask bootstrap/index/static downloads: public Supabase browser credential resolution (_template_browser_supabase_credentials compatibility wrapper), asset versioning (_template_asset_version compatibility wrapper), root page rendering (index compatibility wrapper), generated audio downloads (download_audio compatibility wrapper), static file serving (static_files compatibility wrapper), cached static file serving (serve_cached_files compatibility wrapper), route registration, and idempotent register_legacy_blueprints app-factory registration. legacy_runtime.py should stay a thin compatibility wrapper for those names, and src.app.create_app() should stay a bridge through page_bootstrap_service.register_legacy_blueprints.auth_bootstrap_service owns auth/session bootstrap construction and decisions: LEGACY_AUTH_BOOTSTRAP payload creation, local unauthenticated smoke-mode resolution, request-user context authorization, strict-user resolution, login request parsing, Supabase auth config/header payloads, session payload extraction, OAuth provider/redirect decisions, post-login payloads, strict policy denial payloads, and strict method denial payloads. legacy_runtime.resolve_request_user_id, routes.helpers.get_user_scope_auth_context, routes.helpers.get_strict_user_id, routes.legacy.login_with_email_password, and routes.legacy.start_oauth_sign_in should remain compatibility/Flask-envelope wrappers around the focused service helpers.strict_soundboard_service owns strict Supabase Soundboard metadata, storage-path resolution, clip record/delete/reorder helpers, and transcript-path derivation. legacy_runtime.py should stay a compatibility wrapper for these names.cache_runtime_service owns cache directory initialization, metadata reads/writes, cache file mutation, cleanup, invalidation, static cache resolution, GCS change checks, and clip-cache loading. The cache/job compatibility wrappers are S03-thinned public helper names that remain import-compatible while endpoint envelopes and cache/job behavior stay in focused services.persistent_job_service owns background job creation, update, fetch, JSON safety, and in-memory fallback behavior.draft_service owns non-strict draft listing and creation payload/status behavior.default_model_service owns default-model payloads plus strict-mode get/update endpoint orchestration.pronunciation_service owns pronunciation dictionary route payloads, Supabase edge bridging, and local DB helpers.category_runtime_service owns legacy category seed/provision/copy/move/tree helpers behind explicit dependencies. The category/draft/pronunciation compatibility wrappers are S03-thinned public helper names that remain import-compatible while category, draft, and pronunciation behavior stays in focused services. The compatibility wrappers _category_mgmt_enabled, _ensure_category, seed_legacy_categories, provision_gcs_category, copy_gcs_prefix, move_gcs_prefix, _is_descendant, _fetch_categories, and _build_tree_with_paths are S03-thinned return-only delegates and should not reacquire DB cursor or storage scan bodies.user_settings_service owns user/settings route payloads, local settings defaults/hydration/persistence helpers, settings feature-flag normalization, theme aliases, break-setting aliases, strict-mode unpersisted-field diagnostics, get_user_settings_for_endpoint, and save_user_settings_for_endpoint. legacy_runtime.get_user_settings, legacy_runtime.persist_user_settings, WEB_SETTINGS_SECTIONED_UI_ENABLED, and WEB_SETTINGS_STRUCTURED_BREAKS_ENABLED should remain compatibility wrappers/flags resolved through service helpers, while routes.settings stays a Flask envelope around service payload/status helpers.default_model_service owns default-model payloads plus strict-mode get/update endpoint orchestration through get_default_model_for_endpoint and update_default_model_for_endpoint. legacy_runtime.get_default_model and /api/default-model route handlers should remain compatibility/envelope wrappers rather than re-owning DB or Supabase edge behavior.
storage_config_service owns strict storage/provider configuration: Supabase-only provider mode resolution, required Supabase storage environment resolution, process-wide provider construction, runtime provider lookup, configured-provider selection, and signed URL generation. legacy_runtime._require_supabase_storage_backend, legacy_runtime._resolve_supabase_storage_env_or_raise, legacy_runtime._get_runtime_storage_provider, legacy_runtime._get_configured_storage_provider, and legacy_runtime._generate_signed_url should remain thin compatibility delegates to this service. The M007 S01 guard is scripts/verify_m007_s01_storage_config.py, which rejects provider mode resolution, provider construction, direct env-resolution logic, or signed URL business logic returning to those wrappers.soundboard_route_service owns Soundboard route business bodies for get_soundboard_clips, save_clip_to_soundboard, reorder_soundboard_clips, delete_soundboard_clip, and copy_soundboard_clip, including provider-backed clip loading/saving, reorder persistence, deletion/copy side effects, cache invalidation, strict Supabase branch selection, and legacy response envelopes. legacy_runtime.py should keep those names as return-only delegates through SoundboardRouteDependencies.regeneration_route_service owns regeneration preview/commit/discard/audio route bodies for regenerate_soundboard_clip, commit_regenerated_clip, discard_regeneration_preview, and get_regeneration_preview_audio, including stale-session fallback, provider/GCS commit behavior, rollback, preview streaming, and no-cache response handling. legacy_runtime.py should keep those names as return-only delegates through RegenerationRouteDependencies.combined_route_service owns strict Supabase/auth-aware Combine filename selection for resolve_combine_clip_filenames while default storage ordering remains delegated to combined_service; strict mode fails closed instead of falling back to public Soundboard paths when auth or connection-pool state is missing. legacy_runtime.py should keep this name as a return-only delegate through CombinedRouteDependencies. The Soundboard/regeneration/combine wrappers are guarded by the M007 S02 guard scripts/verify_m007_s02_soundboard_wrappers.py, which rejects missing focused service exports, missing legacy wrapper names, business logic returning to wrappers, and missing inventory ownership markers.speech_service owns speech generation/transcription/provider calls: pronunciation model support checks (model_supports_pronunciation_dictionary, model_uses_v3_pause_tags), glossary/pause application (apply_pronunciation_details), TTS/STT/STS request parsing and artifact helpers, default TTS setting resolution (resolve_default_tts_settings), ElevenLabs generation closure construction (build_generate_voice_fn used by the generate_voice compatibility wrapper), STT file transcription, text-to-speech synthesis, and speech-to-speech synthesis. legacy_runtime.py should stay a thin compatibility wrapper/re-export surface for these names, while routes.tts and routes.stt keep only Flask envelope wiring for /api/text-to-speech, /api/speech-to-text, and /api/speech-to-speech.
scripts/verify_m005_s02_cache_job_extraction.py, scripts/verify_m005_s03_low_risk_extraction.py, scripts/verify_m006_s01_bootstrap_static.py, scripts/verify_m006_s02_auth_bootstrap.py, scripts/verify_m006_s03_user_settings.py, scripts/verify_m006_s04_speech_service.py, scripts/verify_m007_s01_storage_config.py, scripts/verify_m007_s02_soundboard_wrappers.py, and scripts/verify_m007_s03_wrapper_thinning.py.Historical marker for older deterministic guards: future legacy_runtime.py retirement work now means preserving the compatibility shim while preventing any wrapper from reacquiring service-owned behavior.
M007 local retirement proof remains valid for runtime construction ownership, but full compatibility-module deletion is still blocked after M013 by the historical src.legacy_runtime / gb_tts_app import surface and monkeypatch-heavy tests, not by production route adapter imports. legacy_runtime.py is an import-compatible shim whose runtime globals are service-owned compatibility exports; legacy_runtime_adapter.py remains only as a transitional service module and is no longer imported by production routes.
Post-retirement caveats for future agents:
gb_tts_app.py as the external compatibility alias until tests and any external imports are migrated off the historical module name. Deployment entrypoints now use wsgi:app.src.legacy_runtime import surface stable for compatibility tests that verify production response shapes; replace those imports only with dedicated compatibility-removal slices and root/auth/Soundboard/speech/cache/category/draft/pronunciation proof bundles.legacy_runtime_adapter.py in a dedicated cleanup only after confirming no external/internal references to that module path remain. Route-level adapter imports are already forbidden by scripts/verify_m013_s01_adapter_allowlist.py.Additional current guards after M013:
python3 scripts/verify_m013_s01_adapter_allowlist.py
PYTHONPATH=web/python-web-app web/python-web-app/venv/bin/python - <<'PY'
from src.app import create_app
app = create_app()
client = app.test_client()
assert client.get('/health').status_code == 200
assert client.get('/').status_code == 200
print('wsgi smoke OK')
PY
web/python-web-app/venv/bin/pytest \
web/python-web-app/tests/api/test_tts.py \
web/python-web-app/tests/api/test_stt.py \
web/python-web-app/tests/api/test_models.py \
web/python-web-app/tests/api/test_voices.py \
web/python-web-app/tests/api/test_speech_contract_hardening.py \
web/python-web-app/tests/api/test_voice_clone.py \
web/python-web-app/tests/unit/test_legacy_runtime_speech_service_delegation.py \
web/python-web-app/tests/unit/test_runtime_import_boundaries.py \
web/python-web-app/tests/api/test_runtime_entrypoint_closure.py -q
Run these checks after changing the inventory, import policy, or any listed wrapper group:
web/python-web-app/venv/bin/pytest web/python-web-app/tests/unit/test_runtime_import_boundaries.py -q
python3 scripts/verify_m006_s05_validation_coverage.py
python3 scripts/verify_m006_s01_bootstrap_static.py
python3 scripts/verify_m006_s02_auth_bootstrap.py
python3 scripts/verify_m006_s03_user_settings.py
python3 scripts/verify_m006_s04_speech_service.py
python3 scripts/verify_m007_s01_storage_config.py
python3 scripts/verify_m007_s02_soundboard_wrappers.py
python3 scripts/verify_m005_s04_import_boundaries.py
python3 scripts/verify_m005_s04_runtime_closure.py
python3 scripts/verify_m005_s02_cache_job_extraction.py
python3 scripts/verify_m005_s03_low_risk_extraction.py
python3 scripts/verify_m007_s03_wrapper_thinning.py
For runtime-facing changes, also run a root-route render or browser auth bootstrap smoke before claiming the Flask entrypoints still render and authenticate.