Why
The SQLite manager-id convention is inconsistent between the API (which has a dialect resolver) and the ETL flows (which hardcode manager_id), so ETL breaks on any SQLite database bootstrapped by the API.
api/managers.py:136 creates the SQLite table as managers(id INTEGER PRIMARY KEY, ...), and api/managers.py:33 _manager_id_column(conn) correctly returns "id" for SQLite / "manager_id" for Postgres.
- ETL readers do NOT use that resolver — they hardcode
manager_id: etl/news_flow.py:71 (SELECT manager_id, name, aliases FROM managers), etl/daily_diff_flow.py:138, diff_holdings.py:70, etl/activism_flow.py:124.
Failure mode: on a SQLite DB created via the manager API (the documented local/dev path), ETL flows fail with sqlite3.OperationalError: no such column: manager_id. Prod Postgres is unaffected (its column IS manager_id per schema.sql), and CI can miss it when fixtures create a different schema than the app itself creates.
Scope
Make ETL manager-id access dialect-correct so the SQLite-bootstrapped path works end-to-end.
Non-Goals
- Do NOT change the Postgres schema (
manager_id stays canonical there).
- Do NOT duplicate the resolver — reuse the existing
_manager_id_column logic.
Tasks
Acceptance Criteria
Implementation Notes
Audit baseline: main @ e5764a5 on 2026-06-28. Source-verified: API SQLite create at managers.py:136, resolver at managers.py:33, hardcoded ETL reads at the listed lines. Prod-Postgres path is unaffected; this is a SQLite/local-path wiring fix.
Why
The SQLite manager-id convention is inconsistent between the API (which has a dialect resolver) and the ETL flows (which hardcode
manager_id), so ETL breaks on any SQLite database bootstrapped by the API.api/managers.py:136creates the SQLite table asmanagers(id INTEGER PRIMARY KEY, ...), andapi/managers.py:33_manager_id_column(conn)correctly returns"id"for SQLite /"manager_id"for Postgres.manager_id:etl/news_flow.py:71(SELECT manager_id, name, aliases FROM managers),etl/daily_diff_flow.py:138,diff_holdings.py:70,etl/activism_flow.py:124.Failure mode: on a SQLite DB created via the manager API (the documented local/dev path), ETL flows fail with
sqlite3.OperationalError: no such column: manager_id. Prod Postgres is unaffected (its column ISmanager_idperschema.sql), and CI can miss it when fixtures create a different schema than the app itself creates.Scope
Make ETL manager-id access dialect-correct so the SQLite-bootstrapped path works end-to-end.
Non-Goals
manager_idstays canonical there)._manager_id_columnlogic.Tasks
etl/news_flow.py:71,etl/daily_diff_flow.py:138,diff_holdings.py:70,etl/activism_flow.py:124(and any other hardcodedmanager_idreader of themanagerstable). Alternatively, standardize the SQLitemanagersschema onmanager_id.Acceptance Criteria
_ensure_manager_table()+ insert), then call an ETL reader (e.g._fetch_all_manager_ids(conn)/match_entities); current code raisesno such column: manager_id, fixed code returns the inserted manager id.manager_idfails the new test; restoring the resolver passes.Implementation Notes
Audit baseline:
main@e5764a5on 2026-06-28. Source-verified: API SQLite create atmanagers.py:136, resolver atmanagers.py:33, hardcoded ETL reads at the listed lines. Prod-Postgres path is unaffected; this is a SQLite/local-path wiring fix.