atif-sql · Data flow
Section titled “atif-sql · Data flow”The distribution declares exactly one entry point, the console script
atif-sql = "atif_cli.app:main" (packages/atif-cli/pyproject.toml:42), and the main it names
installs a WARNING-and-up loguru sink and hands control to cyclopts — packages/atif-cli/src/atif_cli/app.py:1125.
Every process below therefore begins as a CLI invocation; there is no HTTP, RPC, or queue surface
to enter through.
Two of the three flows below produce the corpus and one consumes it: materialize fills
<corpus_root>/sessions/ (:339), analyze fills <corpus_root>/analytics/ (:627), and
query binds both and runs caller SQL over them (:497). The other commands are subsets of
these three — convert (:225) is one iteration of flow 1’s inner loop, search (:828)
re-enters flow 2’s registration at :886 and adds one kNN statement, embed (:734) writes the
vector store flows 2 and 3 read, and schema (:1055), examples (:963), and status
(:412) answer from static data or stat calls with no downstream participant.
Flow 1: corpus materialization (atif-sql materialize)
Section titled “Flow 1: corpus materialization (atif-sql materialize)”- The
materializecommand resolvesCorpusSettings(pydantic-settings, env prefixATIF_SQL_), then injects the three things the pure use case will not own: theConverterPortadapter, the wall-clock instant, and the harbor / converter version pins stamped into everymeta.json—packages/atif-cli/src/atif_cli/app.py:352. - One pass through the corpus use case runs scan, plan, convert, and write in that order and
returns a
MaterializationReport—packages/atif-corpus/src/atif_corpus/application/materialize.py:476. - The scanner discovers every session under the raw transcript root and separates unreadable
sessions from absent ones, so a
statfailure is never mistaken for a deletion —packages/atif-corpus/src/atif_corpus/infrastructure/scanner.py:143. - The pure planner partitions the scan into to-materialize, up-to-date, and skipped-live using
the previous watermark and the quiescence policy;
forceoverrides staleness but never liveness —packages/atif-corpus/src/atif_corpus/domain/sessions.py:159. - For each planned session the use case calls
converter.convertacross the port; one session’s exception is caught and recorded so a single bad transcript cannot abort the sync —packages/atif-corpus/src/atif_corpus/application/materialize.py:599. - The adapter that satisfies
ConverterPortlives in atif-cli because the independence contract forbids atif-corpus from importing atif-converter; it raises rather than returning an invalid trajectory —packages/atif-cli/src/atif_cli/converter_adapter.py:51. convert_and_auditsnapshots the source files, stages the session into harbor’s expected directory shape and calls harbor’s pinned private method (packages/atif-converter/src/atif_converter/infrastructure/harbor_adapter.py:178), then builds the loss report and edges from the raw records, enriches the trajectory, and refuses the result if any source moved mid-pass —packages/atif-converter/src/atif_converter/application/convert_and_audit.py:105.- The four artifacts are written under
.staging/withmeta.jsonlast, then the whole directory swaps intosessions/<id>/so a reader sees one complete generation or the other (packages/atif-corpus/src/atif_corpus/application/materialize.py:240); the watermark advances only for sessions that succeeded —:608.
Flow 2: SQL read path (atif-sql query '<sql>')
Section titled “Flow 2: SQL read path (atif-sql query '<sql>')”- The
querycommand resolves the corpus root and reads the active embedder’s(model_id, dim)without constructing the embedder, so the vector store’s stamped identity can be checked before anything binds over it —packages/atif-cli/src/atif_cli/app.py:529. - A DuckDB connection is opened with no path or URI, so the engine runs in-process against
memory —
:591. - Registration builds the whole catalog on that connection in a fixed order — raw TEMP tables,
base views, VSS, macros, analytics views, analytics macros — because each later stage binds
against the earlier one at
CREATEtime —packages/atif-duck/src/atif_duck/infrastructure/registry.py:1212. - The raw readers materialize the four corpus artifact kinds as TEMP TABLEs over globs into
<corpus_root>/sessions/, which is where the cost of aqueryinvocation lives: O(corpus) per connection —:196. - Trajectory, edges, and loss readers are semi-joined against the meta table, so a session
directory missing its
meta.jsoncontributes nothing rather than a partial artifact set. This is the read-side half of flow 1’s meta-last write ordering —packages/atif-duck/src/atif_duck/infrastructure/registry.py:221. - The VSS step
ATTACHes the LanceDB store through the lance extension (packages/atif-duck/src/atif_duck/infrastructure/registry.py:887) and reads the store’s stampedmodelanddimback out (packages/atif-duck/src/atif_duck/infrastructure/registry.py:921) before creating any view over it; a store written by a different provider or width raises instead of binding, because vectors from different models live in incompatible spaces and would return numerically valid but meaningless cosine scores —packages/atif-duck/src/atif_duck/domain/embedding_guard.py:46. - The fully-registered connection is then sandboxed: spill directory, memory cap, a directory
allowlist holding only the spill area, a path allowlist holding the individual analytics
parquets,
enable_external_access=false, andlock_configurationlast so caller SQL cannot widen any of it —packages/atif-cli/src/atif_cli/app.py:138. - The caller’s statement executes against the locked connection (
:606) and the cursor drains in batches to stdout — a JSON array of row objects on a pipe, a width-aligned table on a TTY —packages/atif-cli/src/atif_cli/output.py:154.
Flow 3: analytics enrichment (atif-sql analyze --no-dry-run)
Section titled “Flow 3: analytics enrichment (atif-sql analyze --no-dry-run)”- The
analyzecommand loadsAnalyticsSettings, reuses the same corpus-root resolution the other commands share, and stamps explicit--max-sessions/--max-cost-usdceilings over the env defaults so a crontab line carries its spend cap visibly —packages/atif-cli/src/atif_cli/app.py:659. - The pipeline runner builds one shared
CorpusReaderfor every stage, runs the three structural stages, then loops the five LLM stages; the lane selectors andskip_*flags subtract stages from whichever lane runs —packages/atif-analytics/src/atif_analytics/application/analyze.py:36. - Corpus rows are read with stdlib
jsonover<corpus_root>/sessions/<id>/trajectory.jsonbehind a bounded memo — not through DuckDB, which theforbiddenimport contract puts out of this package’s reach —packages/atif-analytics/src/atif_analytics/infrastructure/corpus_reader.py:269. - The structural lane (cluster, then terms, then community) reads vectors straight out of the
Lance store and writes single parquet files, bypassing the sharded cache —
packages/atif-analytics/src/atif_analytics/infrastructure/lance_reader.py:28. - Before the LLM lane starts, one
RunBudgetis constructed from the per-run dollar ceiling (packages/atif-analytics/src/atif_analytics/application/analyze.py:140); all five LLM stages then go through one call site, each receiving the shared reader and that budget, and a stage that finds the budget exhausted is skipped with nothing stamped —:181. - A stage drops the sessions whose checkpoint row still matches their mtime and last step
timestamp, so a re-run costs nothing for unchanged work —
packages/atif-analytics/src/atif_analytics/infrastructure/sqlite_state/checkpointer.py:136. - The concrete provider satisfies
LlmStructuredProviderstructurally, and its synchronous inner method is the only place a Bedrockinvoke_modelcall is issued, under tenacity retry with token usage accumulated against the budget —packages/atif-models/src/atif_models/infrastructure/openai_bedrock.py:258. - Results land as sharded
part-<ns>.parquetfiles under<corpus_root>/analytics/(packages/atif-analytics/src/atif_analytics/infrastructure/parquet_cache.py:90), and each completed session is upserted into the SQLite WAL checkpoint —packages/atif-analytics/src/atif_analytics/infrastructure/sqlite_state/checkpointer.py:179.
See also
Section titled “See also”- processes — 16 shared source citations
- sequences — 16 shared source citations
- module map — 13 shared source citations
- debugging guide — 13 shared source citations
- components — 12 shared source citations