Skip to content

Tier 3 nao walkthrough

This walkthrough treats nao as the Tier 3 analytical surface: a schema-aware AI-IDE for the analyst who is changing SQL, not a dashboard that the platform deploys for readers. The session starts from the local analytical contract: the DuckDB warehouse materialised from the tutorial fixtures and the dbt project under tutorial/serving/dbt. That is the same substrate used by the Evidence incumbent and by the future Tier 2 BI surface, but nao enters at a different moment. The analyst is inside the authoring loop, asking why a query fails across publishers and deciding whether the fix belongs in staging, evaluation, or lesson prose.

Annotated nao screenshot showing the DuckDB warehouse and tutorial/serving/dbt project connected for schema discovery

The first flow is connection and schema discovery. In nao, the analyst opens a workspace that points at the DuckDB file produced by the serving module and at the dbt project root. The useful view is not only a table list. It joins dbt model metadata, column descriptions, tests, and file paths into one navigation surface. stg_ebnerd_articles shows article_id, title, category, published_at, sentiment_score, ner_entities, and publisher. stg_adressa_articles shows the same canonical article identity fields but no sentiment_score. stg_mind_articles adds subcategory, abstract, and url, keeps published_at nullable, and also has no sentiment column.

That difference is the point of the lesson. ADR-0006 says the analytical contract is for people asking direct questions of the warehouse, but a direct question is not allowed to flatten publisher-specific data into a fake common shape. The nao lineage panel makes that visible before the analyst writes a fix. Selecting category shows how EB-NeRD’s single token, Adressa’s slash-separated path, and MIND’s broader category taxonomy all arrive at a shared column name through different staging choices. Selecting sentiment_score shows that only EB-NeRD contributes the column. The absence is not an error; it is a contract detail downstream code must respect.

Annotated nao screenshot showing column lineage across EB-NeRD, Adressa, and MIND staging models

The second flow is the copilot suggestion. The analyst asks: “Why does this cross-publisher sentiment query fail when I include Adressa and MIND, and what would be the smallest honest fix?” A naive query groups all article staging models together and calls avg(sentiment_score). That feels natural if the analyst has only worked with EB-NeRD, but it breaks the moment Adressa enters because Adressa lacks sentiment, and it misleads for MIND because MIND brings a different category taxonomy and no article-level sentiment. The right fix is not to invent neutral scores. The right fix is to make availability explicit.

Nao’s useful suggestion is a small SQL rewrite: keep publisher, keep a normalised category_family for comparison, and compute sentiment only where the source actually exposes it. The suggestion reads the dbt schema docs and the model SQL, so it can explain why sentiment_score should be wrapped as CASE WHEN publisher = 'ebnerd' THEN sentiment_score END or joined through an EB-NeRD-only metric CTE rather than coalesced to zero. It also suggests a separate sentiment_available flag. That flag is what makes the degradation graceful: dashboard, BI, and evaluation consumers can display “not available” instead of treating missing measurement as neutral editorial sentiment.

This is where nao is asymmetric to Tier 1 and Tier 2. A static generator can publish the final explanation, and a BI server can let an analyst filter the finished metric. Neither one should be the place where schema drift, dbt model docs, column tests, and proposed SQL edits are negotiated. Nao lives in the editor loop, close to the files and the tests. It helps the analyst change the contract without hiding the contract.

Annotated nao screenshot showing an AI copilot SQL fix for cross-publisher sentiment availability and category-family comparison

The third flow is the before/after diff. The analyst accepts the suggested rewrite into a scratch model or a lesson query and nao shows the before/after diff beside the lineage graph. The before side has one implicit assumption: every publisher can support avg(sentiment_score). The after side splits that assumption into two fields, sentiment_available and mean_sentiment_when_available, and leaves category comparison as a separate normalisation step. That diff matters because it is reviewable. The reviewer can see the exact query change instead of reading a chat transcript and guessing what landed.

The lineage view then propagates downstream impact. A change that only touches the analytical metric should not imply that article_embeddings or the app contract has changed. A change that alters staging columns should light up the models, tests, and docs that read those columns. In this walkthrough, the safe boundary is clear: the staging contract already documents the absence of sentiment for Adressa and MIND, so the fix belongs in the analytical query and lesson framing. Nao helps prove that by showing which downstream surfaces would change and which would stay untouched.

ADR-0023 is the framing reference for this Tier 3 role. It says nao packages schema, docs, rules, tests, and platform metadata into a conversational analytics surface over the DuckDB/Parquet analytical contract. Module 13 narrows that into a tier distinction. Nao is not Tier 1 because it does not produce durable static pages for readers or stakeholders. It is not Tier 2 because it is not a deployed surface for interactive BI sessions. It is not a deployed surface at all, and it does not serve readers. It serves the analyst or engineer who is authoring, debugging, and testing analytical work before a public surface gets rebuilt.

That limitation is also the reason to include it. The platform needs Tier 1 for permanent reference pages and Tier 2 for governed exploration, but it also needs a place where the analyst can ask schema-aware questions while making edits. The Adressa/MIND sentiment case is the smallest honest example: nao does not make missing columns disappear; it makes the missingness visible early enough that the deployed analytical surfaces can stay truthful.