2026-02-13 16:53:51 | INFO    | atelier | Logging initialised (level=DEBUG, file=/home/modelling/atelier.log)
2026-02-13 16:53:51 | INFO    | uvicorn.error | Started server process [179383]
2026-02-13 16:53:51 | INFO    | uvicorn.error | Waiting for application startup.
2026-02-13 16:53:51 | INFO    | atelier | Starting Atelier lifespan — ensuring data dirs, schema, and WAL mode
2026-02-13 16:53:51 | INFO    | atelier | Data directories ready
2026-02-13 16:53:51 | INFO    | atelier.db.migrations | [migrations] ensuring schema (create_all)
2026-02-13 16:53:51 | INFO    | atelier.db.engine | [db/engine] creating async engine  url=sqlite+aiosqlite:////home/ralph/.atelier/atelier.db
2026-02-13 16:53:51 | DEBUG   | atelier.db.engine | [db/engine] engine created successfully
2026-02-13 16:53:51 | INFO    | atelier.db.migrations | [migrations] base tables ensured
2026-02-13 16:53:51 | INFO    | atelier.db.migrations | [migrations] running 6 column migrations
2026-02-13 16:53:51 | DEBUG   | atelier.db.migrations | [migrations] column models.df_model already exists
2026-02-13 16:53:51 | DEBUG   | atelier.db.migrations | [migrations] column models.df_resid already exists
2026-02-13 16:53:51 | DEBUG   | atelier.db.migrations | [migrations] column models.n_validation already exists
2026-02-13 16:53:51 | DEBUG   | atelier.db.migrations | [migrations] column models.n_params already exists
2026-02-13 16:53:51 | DEBUG   | atelier.db.migrations | [migrations] column projects.config already exists
2026-02-13 16:53:51 | DEBUG   | atelier.db.migrations | [migrations] column projects.n_versions already exists
2026-02-13 16:53:51 | INFO    | atelier.db.migrations | [migrations] schema migration complete
2026-02-13 16:53:51 | INFO    | atelier | Database schema up-to-date
2026-02-13 16:53:51 | INFO    | atelier.db.engine | [db/engine] enabling WAL journal mode
2026-02-13 16:53:51 | INFO    | atelier.db.engine | [db/engine] WAL mode enabled
2026-02-13 16:53:51 | INFO    | atelier | WAL mode enabled — startup complete
2026-02-13 16:53:51 | INFO    | uvicorn.error | Application startup complete.
2026-02-13 16:53:51 | INFO    | uvicorn.error | Uvicorn running on http://127.0.0.1:8457 (Press CTRL+C to quit)
2026-02-13 16:53:53 | INFO    | uvicorn.access | 127.0.0.1:46736 - "GET / HTTP/1.1" 200
2026-02-13 16:53:53 | INFO    | uvicorn.access | 127.0.0.1:46736 - "GET /favicon.ico HTTP/1.1" 200
2026-02-13 16:53:54 | DEBUG   | atelier.db.engine | [db/engine] opening new async session
2026-02-13 16:53:54 | DEBUG   | atelier.db.engine | [db/engine] creating session factory
2026-02-13 16:53:54 | INFO    | atelier.api.projects | [projects/list] fetching all projects
2026-02-13 16:53:54 | INFO    | atelier.api.projects | [projects/list] returning 2 projects
2026-02-13 16:53:54 | INFO    | uvicorn.access | 127.0.0.1:46736 - "GET /api/projects HTTP/1.1" 200
2026-02-13 16:53:54 | DEBUG   | atelier.db.engine | [db/engine] async session closed
2026-02-13 16:53:56 | DEBUG   | atelier.db.engine | [db/engine] opening new async session
2026-02-13 16:53:56 | INFO    | atelier.api.projects | [projects/get] project_id=639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:53:56 | DEBUG   | atelier.api.projects | [projects/get] found project 'renewal'  n_versions=2  has_config=True
2026-02-13 16:53:56 | INFO    | uvicorn.access | 127.0.0.1:46736 - "GET /api/projects/639980e4-fa6b-479f-a3ed-01d353b57b33 HTTP/1.1" 200
2026-02-13 16:53:56 | DEBUG   | atelier.db.engine | [db/engine] async session closed
2026-02-13 16:53:56 | INFO    | uvicorn.access | 127.0.0.1:46736 - "GET /favicon.ico HTTP/1.1" 200
2026-02-13 16:53:56 | INFO    | atelier.api.explore | [explore] request: response=RenewalFlag  family=binomial  offset=None  split=Group  dataset_path=/home/ralph/.atelier/projects/_uploads/48a5c6c7-d510-4682-9173-682327a78f59.parquet  project_id=639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:53:56 | INFO    | atelier.services.dataset_service | [load_dataframe] path=/home/ralph/.atelier/projects/_uploads/48a5c6c7-d510-4682-9173-682327a78f59.parquet  exists=True  suffix=.parquet
2026-02-13 16:53:56 | INFO    | atelier.services.dataset_service | [load_dataframe] casting 2 Decimal columns to Float64: ['Invited_Core_Net', 'InvitedPremiumDiff']
2026-02-13 16:53:56 | INFO    | atelier.services.dataset_service | [load_dataframe] loaded 239064 rows x 13 cols from 48a5c6c7-d510-4682-9173-682327a78f59.parquet
2026-02-13 16:53:56 | DEBUG   | atelier.services.dataset_service | [load_dataframe] dtypes: {'RenewalFlag': 'Int32', 'Group': 'Int32', 'Invited_Scheme': 'String', 'Scheme': 'String', 'Invited_Core_Net': 'Float64', 'FinanceGroup': 'String', 'InvitedPremiumDiff': 'Float64', 'TotalNumberOfQuotesPrediction': 'Float64', 'DifferenceToMarket': 'Float64', 'PreviousRenewal': 'Int32', 'PROPOSER_AGE': 'Int32', 'PROPERTY_OCCUPANCY_OCC_STATUS_Unoccupied': 'Int32', 'Cover_Type': 'String'}
2026-02-13 16:53:56 | INFO    | atelier.api.explore | [explore] loaded dataframe: rows=239064  cols=13
2026-02-13 16:53:56 | INFO    | atelier.services.dataset_service | [apply_split] splitting on column='Group'  mapping={'0': 'train', '1': 'train', '2': 'train', '3': 'train', '4': 'validation', '5': 'holdout'}
2026-02-13 16:53:56 | DEBUG   | atelier.services.dataset_service | [apply_split] train_vals=['0', '1', '2', '3']  val_vals=['4']
2026-02-13 16:53:56 | INFO    | atelier.services.dataset_service | [apply_split] result: train=181185 rows  validation=57842 rows  (from 239064 total)
2026-02-13 16:53:56 | INFO    | atelier.api.explore | [explore] after split: train_rows=181185  validation_rows=57842
2026-02-13 16:53:56 | DEBUG   | atelier.services.dataset_service | [classify_columns] 13 total columns  reserved={'Group', 'RenewalFlag'}  cat_threshold=50
2026-02-13 16:53:56 | INFO    | atelier.services.dataset_service | [classify_columns] result: 6 categorical, 5 continuous (skipped 0)
2026-02-13 16:53:56 | INFO    | atelier.api.explore | [explore] classified factors: 6 categorical, 5 continuous  reserved={'Group', 'RenewalFlag'}
2026-02-13 16:53:56 | DEBUG   | atelier.api.explore | [explore] cat_factors=['Invited_Scheme', 'Scheme', 'FinanceGroup', 'PreviousRenewal', 'PROPERTY_OCCUPANCY_OCC_STATUS_Unoccupied', 'Cover_Type']
2026-02-13 16:53:56 | DEBUG   | atelier.api.explore | [explore] cont_factors=['Invited_Core_Net', 'InvitedPremiumDiff', 'TotalNumberOfQuotesPrediction', 'DifferenceToMarket', 'PROPOSER_AGE']
2026-02-13 16:53:56 | DEBUG   | atelier.api.explore | [explore] calling rs.explore_data with kwargs keys=['data', 'response', 'family', 'categorical_factors', 'continuous_factors']
2026-02-13 16:54:01 | INFO    | atelier.api.explore | [explore] rs.explore_data completed in 4836ms  result_keys=['data_summary', 'factor_stats', 'missing_values', 'univariate_tests', 'correlations', 'cramers_v', 'vif', 'zero_inflation', 'overdispersion', 'interaction_candidates', 'response_stats']
2026-02-13 16:54:01 | DEBUG   | atelier.api.explore | [explore] fitting null model with kwargs keys=['response', 'terms', 'data', 'family']
2026-02-13 16:54:01 | DEBUG   | atelier.api.explore | [explore] null model fitted, computing diagnostics
2026-02-13 16:54:02 | INFO    | atelier.api.explore | [explore] null model diagnostics completed in 1018ms  diag_keys=['model_summary', 'train_test', 'calibration', 'residual_summary', 'factors', 'interaction_candidates', 'model_comparison', 'warnings', 'vif', 'smooth_terms', 'coefficient_summary', 'factor_deviance', 'lift_chart', 'partial_dependence', 'overdispersion', 'spline_info', 'base_predictions_comparison']
2026-02-13 16:54:02 | INFO    | atelier.api.explore | [explore] saving null model for project_id=639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:02 | DEBUG   | atelier.db.engine | [db/engine] opening new async session
2026-02-13 16:54:02 | INFO    | atelier.api.models | [models/history] project_id=639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:02 | INFO    | atelier.api.explore | [explore] returning result with 12 top-level keys
2026-02-13 16:54:02 | INFO    | uvicorn.access | 127.0.0.1:46736 - "POST /api/explore HTTP/1.1" 200
2026-02-13 16:54:02 | INFO    | atelier.api.models | [models/history] found 2 versions for project 639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:02 | DEBUG   | atelier.api.models | [models/history] returning 2 summaries
2026-02-13 16:54:02 | INFO    | uvicorn.access | 127.0.0.1:46748 - "GET /api/models/639980e4-fa6b-479f-a3ed-01d353b57b33/history HTTP/1.1" 200
2026-02-13 16:54:02 | DEBUG   | atelier.db.engine | [db/engine] async session closed
2026-02-13 16:54:02 | DEBUG   | atelier.db.engine | [db/engine] opening new async session
2026-02-13 16:54:02 | INFO    | atelier.api.models | [models/history] project_id=639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:02 | INFO    | atelier.api.models | [models/history] found 2 versions for project 639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:02 | DEBUG   | atelier.api.models | [models/history] returning 2 summaries
2026-02-13 16:54:02 | INFO    | uvicorn.access | 127.0.0.1:46748 - "GET /api/models/639980e4-fa6b-479f-a3ed-01d353b57b33/history HTTP/1.1" 200
2026-02-13 16:54:02 | DEBUG   | atelier.db.engine | [db/engine] async session closed
2026-02-13 16:54:02 | DEBUG   | atelier.db.engine | [db/engine] opening new async session
2026-02-13 16:54:02 | INFO    | atelier.api.models | [models/detail] model_id=e02f09f5-0c13-4a42-b6be-1eb12cc8150c
2026-02-13 16:54:02 | INFO    | atelier.api.models | [models/detail] returning model v2  project_id=639980e4-fa6b-479f-a3ed-01d353b57b33  status=fitted  n_obs=181185
2026-02-13 16:54:02 | INFO    | uvicorn.access | 127.0.0.1:46736 - "GET /api/models/detail/e02f09f5-0c13-4a42-b6be-1eb12cc8150c HTTP/1.1" 200
2026-02-13 16:54:02 | DEBUG   | atelier.db.engine | [db/engine] async session closed
2026-02-13 16:54:08 | INFO    | atelier.api.fit | [fit] request: response=RenewalFlag  family=binomial  link=logit  offset=None  weights=None  n_terms=1  split=Group  dataset_path=/home/ralph/.atelier/projects/_uploads/48a5c6c7-d510-4682-9173-682327a78f59.parquet
2026-02-13 16:54:08 | DEBUG   | atelier.api.fit | [fit] term[0]: column=InvitedPremiumDiff  type=linear  df=None  k=None  mono=None  expr=None
2026-02-13 16:54:08 | INFO    | atelier.services.dataset_service | [load_dataframe] path=/home/ralph/.atelier/projects/_uploads/48a5c6c7-d510-4682-9173-682327a78f59.parquet  exists=True  suffix=.parquet
2026-02-13 16:54:08 | INFO    | atelier.services.dataset_service | [load_dataframe] casting 2 Decimal columns to Float64: ['Invited_Core_Net', 'InvitedPremiumDiff']
2026-02-13 16:54:08 | INFO    | atelier.services.dataset_service | [load_dataframe] loaded 239064 rows x 13 cols from 48a5c6c7-d510-4682-9173-682327a78f59.parquet
2026-02-13 16:54:08 | DEBUG   | atelier.services.dataset_service | [load_dataframe] dtypes: {'RenewalFlag': 'Int32', 'Group': 'Int32', 'Invited_Scheme': 'String', 'Scheme': 'String', 'Invited_Core_Net': 'Float64', 'FinanceGroup': 'String', 'InvitedPremiumDiff': 'Float64', 'TotalNumberOfQuotesPrediction': 'Float64', 'DifferenceToMarket': 'Float64', 'PreviousRenewal': 'Int32', 'PROPOSER_AGE': 'Int32', 'PROPERTY_OCCUPANCY_OCC_STATUS_Unoccupied': 'Int32', 'Cover_Type': 'String'}
2026-02-13 16:54:08 | INFO    | atelier.api.fit | [fit] loaded dataframe: rows=239064  cols=13
2026-02-13 16:54:08 | INFO    | atelier.services.dataset_service | [apply_split] splitting on column='Group'  mapping={'0': 'train', '1': 'train', '2': 'train', '3': 'train', '4': 'validation', '5': 'holdout'}
2026-02-13 16:54:08 | DEBUG   | atelier.services.dataset_service | [apply_split] train_vals=['0', '1', '2', '3']  val_vals=['4']
2026-02-13 16:54:08 | INFO    | atelier.services.dataset_service | [apply_split] result: train=181185 rows  validation=57842 rows  (from 239064 total)
2026-02-13 16:54:08 | INFO    | atelier.api.fit | [fit] after split: train_rows=181185  validation_rows=57842
2026-02-13 16:54:08 | DEBUG   | atelier.api.fit | [fit] built terms_dict with 1 entries: ['InvitedPremiumDiff']
2026-02-13 16:54:08 | DEBUG   | atelier.api.fit | [fit] calling rs.glm_dict with kwargs keys=['response', 'terms', 'data', 'family', 'link']
2026-02-13 16:54:08 | INFO    | atelier.api.fit | [fit] model fit completed in 48ms
2026-02-13 16:54:08 | DEBUG   | atelier.api.fit | [fit] extracting summary and coefficient table
2026-02-13 16:54:08 | INFO    | atelier.api.fit | [fit] model has 2 parameters / features
2026-02-13 16:54:08 | DEBUG   | atelier.api.fit | [fit] coefficient table built with 2 rows
2026-02-13 16:54:08 | INFO    | atelier.api.fit | [fit] metrics: deviance=228745.42117755936  null_deviance=249115.34207660166  aic=228749.42117755953  bic=228769.63572533496
2026-02-13 16:54:08 | DEBUG   | atelier.services.dataset_service | [classify_columns] 13 total columns  reserved={'Group', 'RenewalFlag'}  cat_threshold=50
2026-02-13 16:54:08 | INFO    | atelier.services.dataset_service | [classify_columns] result: 6 categorical, 5 continuous (skipped 0)
2026-02-13 16:54:08 | INFO    | atelier.api.fit | [fit] diagnostics: 6 cat factors, 5 cont factors  reserved={'Group', 'RenewalFlag'}
2026-02-13 16:54:09 | INFO    | atelier.api.fit | [fit] diagnostics completed in 1056ms  diag_keys=['model_summary', 'train_test', 'calibration', 'residual_summary', 'factors', 'interaction_candidates', 'model_comparison', 'warnings', 'vif', 'smooth_terms', 'coefficient_summary', 'factor_deviance', 'lift_chart', 'partial_dependence', 'overdispersion', 'spline_info', 'base_predictions_comparison']
2026-02-13 16:54:09 | INFO    | atelier.api.fit | [fit] returning result: n_obs=181185  n_params=2  n_terms=1  fit_ms=48
2026-02-13 16:54:09 | INFO    | uvicorn.access | 127.0.0.1:57946 - "POST /api/fit HTTP/1.1" 200
2026-02-13 16:54:09 | DEBUG   | atelier.db.engine | [db/engine] opening new async session
2026-02-13 16:54:09 | INFO    | atelier.api.models | [models/save] project_id=639980e4-fa6b-479f-a3ed-01d353b57b33  response=RenewalFlag  family=binomial  n_terms=1  deviance=228745.42117755936  aic=228749.42117755953  n_obs=181185  fit_ms=48
2026-02-13 16:54:09 | DEBUG   | atelier.api.models | [models/save] committing v3 to DB for project 'renewal'
2026-02-13 16:54:09 | INFO    | atelier.api.models | [models/save] saved model v3 (id=c0b49b78-0ad7-4754-a405-6a5453d0562e) for project 'renewal' (id=639980e4-fa6b-479f-a3ed-01d353b57b33)
2026-02-13 16:54:09 | INFO    | uvicorn.access | 127.0.0.1:57946 - "POST /api/models/save HTTP/1.1" 200
2026-02-13 16:54:09 | DEBUG   | atelier.db.engine | [db/engine] async session closed
2026-02-13 16:54:09 | DEBUG   | atelier.db.engine | [db/engine] opening new async session
2026-02-13 16:54:09 | INFO    | atelier.api.models | [models/history] project_id=639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:09 | INFO    | atelier.api.models | [models/history] found 3 versions for project 639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:09 | DEBUG   | atelier.api.models | [models/history] returning 3 summaries
2026-02-13 16:54:09 | INFO    | uvicorn.access | 127.0.0.1:57946 - "GET /api/models/639980e4-fa6b-479f-a3ed-01d353b57b33/history HTTP/1.1" 200
2026-02-13 16:54:09 | DEBUG   | atelier.db.engine | [db/engine] async session closed
2026-02-13 16:54:19 | INFO    | atelier.api.explore | [explore] request: response=RenewalFlag  family=binomial  offset=None  split=Group  dataset_path=/home/ralph/.atelier/projects/_uploads/48a5c6c7-d510-4682-9173-682327a78f59.parquet  project_id=639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:19 | INFO    | atelier.services.dataset_service | [load_dataframe] path=/home/ralph/.atelier/projects/_uploads/48a5c6c7-d510-4682-9173-682327a78f59.parquet  exists=True  suffix=.parquet
2026-02-13 16:54:19 | INFO    | atelier.services.dataset_service | [load_dataframe] casting 2 Decimal columns to Float64: ['Invited_Core_Net', 'InvitedPremiumDiff']
2026-02-13 16:54:19 | INFO    | atelier.services.dataset_service | [load_dataframe] loaded 239064 rows x 13 cols from 48a5c6c7-d510-4682-9173-682327a78f59.parquet
2026-02-13 16:54:19 | DEBUG   | atelier.services.dataset_service | [load_dataframe] dtypes: {'RenewalFlag': 'Int32', 'Group': 'Int32', 'Invited_Scheme': 'String', 'Scheme': 'String', 'Invited_Core_Net': 'Float64', 'FinanceGroup': 'String', 'InvitedPremiumDiff': 'Float64', 'TotalNumberOfQuotesPrediction': 'Float64', 'DifferenceToMarket': 'Float64', 'PreviousRenewal': 'Int32', 'PROPOSER_AGE': 'Int32', 'PROPERTY_OCCUPANCY_OCC_STATUS_Unoccupied': 'Int32', 'Cover_Type': 'String'}
2026-02-13 16:54:19 | INFO    | atelier.api.explore | [explore] loaded dataframe: rows=239064  cols=13
2026-02-13 16:54:19 | INFO    | atelier.services.dataset_service | [apply_split] splitting on column='Group'  mapping={'0': 'train', '1': 'train', '2': 'train', '3': 'train', '4': 'validation', '5': 'holdout'}
2026-02-13 16:54:19 | DEBUG   | atelier.services.dataset_service | [apply_split] train_vals=['0', '1', '2', '3']  val_vals=['4']
2026-02-13 16:54:19 | INFO    | atelier.services.dataset_service | [apply_split] result: train=181185 rows  validation=57842 rows  (from 239064 total)
2026-02-13 16:54:19 | INFO    | atelier.api.explore | [explore] after split: train_rows=181185  validation_rows=57842
2026-02-13 16:54:19 | DEBUG   | atelier.services.dataset_service | [classify_columns] 13 total columns  reserved={'Group', 'RenewalFlag'}  cat_threshold=50
2026-02-13 16:54:19 | INFO    | atelier.services.dataset_service | [classify_columns] result: 6 categorical, 5 continuous (skipped 0)
2026-02-13 16:54:19 | INFO    | atelier.api.explore | [explore] classified factors: 6 categorical, 5 continuous  reserved={'Group', 'RenewalFlag'}
2026-02-13 16:54:19 | DEBUG   | atelier.api.explore | [explore] cat_factors=['Invited_Scheme', 'Scheme', 'FinanceGroup', 'PreviousRenewal', 'PROPERTY_OCCUPANCY_OCC_STATUS_Unoccupied', 'Cover_Type']
2026-02-13 16:54:19 | DEBUG   | atelier.api.explore | [explore] cont_factors=['Invited_Core_Net', 'InvitedPremiumDiff', 'TotalNumberOfQuotesPrediction', 'DifferenceToMarket', 'PROPOSER_AGE']
2026-02-13 16:54:19 | DEBUG   | atelier.api.explore | [explore] calling rs.explore_data with kwargs keys=['data', 'response', 'family', 'categorical_factors', 'continuous_factors']
2026-02-13 16:54:24 | INFO    | atelier.api.explore | [explore] rs.explore_data completed in 4628ms  result_keys=['data_summary', 'factor_stats', 'missing_values', 'univariate_tests', 'correlations', 'cramers_v', 'vif', 'zero_inflation', 'overdispersion', 'interaction_candidates', 'response_stats']
2026-02-13 16:54:24 | DEBUG   | atelier.api.explore | [explore] fitting null model with kwargs keys=['response', 'terms', 'data', 'family']
2026-02-13 16:54:24 | DEBUG   | atelier.api.explore | [explore] null model fitted, computing diagnostics
2026-02-13 16:54:25 | INFO    | atelier.api.explore | [explore] null model diagnostics completed in 973ms  diag_keys=['model_summary', 'train_test', 'calibration', 'residual_summary', 'factors', 'interaction_candidates', 'model_comparison', 'warnings', 'vif', 'smooth_terms', 'coefficient_summary', 'factor_deviance', 'lift_chart', 'partial_dependence', 'overdispersion', 'spline_info', 'base_predictions_comparison']
2026-02-13 16:54:25 | INFO    | atelier.api.explore | [explore] saving null model for project_id=639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:25 | DEBUG   | atelier.db.engine | [db/engine] opening new async session
2026-02-13 16:54:25 | INFO    | atelier.api.models | [models/history] project_id=639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:25 | INFO    | uvicorn.access | 127.0.0.1:57242 - "GET / HTTP/1.1" 200
2026-02-13 16:54:25 | INFO    | atelier.api.models | [models/history] found 3 versions for project 639980e4-fa6b-479f-a3ed-01d353b57b33
2026-02-13 16:54:25 | DEBUG   | atelier.api.models | [models/history] returning 3 summaries
2026-02-13 16:54:25 | INFO    | uvicorn.access | 127.0.0.1:57228 - "GET /api/models/639980e4-fa6b-479f-a3ed-01d353b57b33/history HTTP/1.1" 200
2026-02-13 16:54:25 | DEBUG   | atelier.db.engine | [db/engine] async session closed
2026-02-13 16:54:25 | INFO    | atelier.api.explore | [explore] returning result with 12 top-level keys
2026-02-13 16:54:25 | INFO    | uvicorn.access | 127.0.0.1:57222 - "POST /api/explore HTTP/1.1" 200
2026-02-13 16:54:25 | INFO    | uvicorn.access | 127.0.0.1:57228 - "GET /favicon.ico HTTP/1.1" 200
2026-02-13 16:54:25 | DEBUG   | atelier.db.engine | [db/engine] opening new async session
2026-02-13 16:54:25 | INFO    | atelier.api.projects | [projects/list] fetching all projects
2026-02-13 16:54:25 | INFO    | atelier.api.projects | [projects/list] returning 2 projects
2026-02-13 16:54:25 | INFO    | uvicorn.access | 127.0.0.1:57228 - "GET /api/projects HTTP/1.1" 200
2026-02-13 16:54:25 | DEBUG   | atelier.db.engine | [db/engine] async session closed
