Config / settings architecture

Live map of how TranscriptX resolves, validates, and exposes knobs. Historical migration plans live under docs/archive/plans/ (config_knobs_refactor_plan.md, config_ownership_collapse_plan.md, pydantic_migration.md) — do not treat archived metrics as current.

Ownership snapshot (authoritative)

Enforced by tests/core/config/test_registry_ownership.py against tests/core/config/fixtures/registry_ownership_snapshot.json:

Metric

Live value

Pydantic pilots

53

Pydantic-owned flattened registry leaves

720

Permanent non-Pydantic baseline leaves

16

Total registry leaves

736

Baseline leaves include profile activation selectors (active_*_profile), core_mode, use_emojis, and intentional analysis.chart_descriptions.* keys.

Dual stack

flowchart TD
  defaults["Dataclass defaults\nTranscriptXConfig facade"]
  file["JSON file\nfile_overrides"]
  profiles["Module profiles\nprofile_loading"]
  env["TRANSCRIPTX_* env\nenv_key_registry"]
  facade["Runtime facade\nget_config()"]

  defaults --> file --> profiles --> env --> facade

  project["project config.json"]
  draft["draft / run override"]
  resolve["resolve_effective_config"]
  validate["core.config.validate_config"]
  run["RunConfigurator.set_config"]
  ui["Settings UI"]

  project --> resolve
  draft --> resolve
  resolve --> validate --> run
  resolve --> ui
  ui -->|save| project
  ui -->|save| draft

Stack

Location

Role

A — runtime facade

src/transcriptx/core/utils/config/

Attribute API modules read (get_config().analysis.*)

B — registry / pilots

src/transcriptx/core/config/

Pydantic models, build_registry(), UI metadata, leaf validation, persistence

Bridge: core/config/pydantic_bridge.py (PYDANTIC_REGISTRY_PILOTS).

Facade load order

TranscriptXConfig.__init__ (utils/config/main.py):

defaults < optional JSON file < active module/workflow profiles < env (env wins).

Effective config (Settings + runs)

resolve_effective_config (core/config/resolver.py):

default < project < draft/run override < env, then validate. Rebuild still uses a temp JSON + _load_from_file roundtrip (known debt).

Surfaces

Surface

Entry

Settings hub

web/page_modules/settings.py + web/ui/settings/*

Profiles page

web/page_modules/profiles.py + app/controllers/profile_controller.py

Pipeline

pipeline/run_configurator.py

Env

utils/config/env_key_registry.pyENV_KEY_REGISTRY vs INFRA_ENV_ALLOWLIST

Profile targets

core/config/gui_support.py (PROFILE_TARGET_*, COMMON_SETTINGS_SCHEMA)

Profile CRUD

utils/profile_manager.py under PROFILES_DIR

User-facing guide: settings.md.

Validation (two paths today)

Path

Module

Used by

Canonical leaf / pilot

core/config/validation.py

Settings UI, run configurator

Object-level legacy

utils/config_validator.py

Still called from file_overrides._validate_candidate in addition to leaf validation

Unifying these is a hardening follow-up — see settings_knobs_assessment.md.

Profile targets

Supported ProfileManager targets: workflow, topic_modeling, semantic_similarity, acts, tag_extraction, qa_analysis, temporal_dynamics, vectorization, llm_models.

Note: analysis.semantic_similarity_profiles (in-config fast/balanced/deep) is a separate mapping store that shares activation-key vocabulary with the disk ProfileManager target — do not merge casually.

Extension checklist

  1. Add/change a knob in the owning Pydantic model under core/config/models/.

  2. Keep runtime facade attributes compatible (delegation hydrate if the subtree is delegated).

  3. Update ownership snapshot / goldens when registry leaf counts change.

  4. Add env mapping only via ENV_KEY_REGISTRY (or infra allowlist if not a bag key); update .env.example.

  5. Curate into COMMON_SETTINGS_SCHEMA only when the knob belongs in guided Settings UX.

  6. Document user-visible behaviour in settings.md / module runtime notes — not in archived plans.