Skip to content

THE INCQL BOOK

3. Inspect the plan

Use Prism-backed inspection to explain the lazy work before a backend executes it.

Part II

Explain and execute it

Chapter 1 of 3

Goal

Inspect the review plan and its lineage without executing DataFusion. Locate the plan target, output schema, Prism nodes, and lineage relationships that explain the deferred work.

Prism is the planning layer

IncQL is the library and public data-logic surface. Prism is its internal logical planning engine; the two names are related but not interchangeable. Today, the LazyFrame path owns Prism state, which is why inspect_plan(...) and inspect_lineage(...) can read this plan locally.

Inspection is read-only. It does not bind a physical backend, inspect a DataFusion physical plan, or turn local evidence into a Substrait payload.

With this example, you are reading the same ReadNamedTable → Limit plan at two levels of detail. inspect_plan(plan.clone()) produces the full PlanInspection, while inspect_lineage(plan) returns only its lineage graph; cloning preserves a carrier for the second call. Both functions read the Prism store and current tip locally, so their node and edge counts explain authored intent rather than backend execution.

Query under glass · local plan evidence

See what Prism knows—and where inspection stops

The checkpoint builds one deferred carrier, then reads two views of its local Prism state. Neither inspection call crosses into backend execution.

  1. 01
    Deferred review planDescribe a named read followed by a limit
    orders: LazyFrame[Order] = session.read_csv(
        "tutorial_orders",
        "orders.csv",
    )?
    plan = orders.limit(3) # (1)!
    
    1. Inspection target. limit(3) returns the deferred LazyFrame whose current Prism tip is the new Limit node. Assigning it to plan gives both inspection functions the same ReadNamedTable → Limit target; no backend work occurs here.

    Owner
    Authoring surface
    Artifact
    LazyFrame[Order]
    Knowable now
    The authored ReadNamedTable → Limit intent
  2. 02
    Prism inspectionRead structure and lineage from local plan state
    inspection = inspect_plan(plan.clone()) # (1)!
    lineage = inspect_lineage(plan) # (2)!
    
    1. Full inspection. inspect_plan(...) consumes a LazyFrame value and returns the complete PlanInspection: plan targets, schemas, authored and rewritten nodes, lineage, requirements, artifacts, diagnostics, and unsupported-evidence markers. Passing plan.clone() preserves another carrier value for the next call.

    2. Lineage-only view. inspect_lineage(...) consumes the remaining carrier and returns its LineageGraph directly. Use this narrower function when callers need relationships rather than the complete inspection record. Like inspect_plan(...), it reads local Prism state without executing the plan.

    Owner
    Prism inspection
    Artifact
    PlanInspection and lineage graph
    Knowable now
    Plan target, output schema, authored nodes, and lineage relationships
  3. 03
    Local evidence returnReport plan facts without materialising rows
    Plan target
    One local Prism identifier
    Authored nodes
    2
    Lineage edges
    8
    PlanInspection Lineage graph

inspect_plan(...) returns a structured PlanInspection. inspect_lineage(...) exposes the lineage graph from the same Prism-backed state when that graph is all a caller needs. The plan identifier printed by the checkpoint is a local evidence anchor, not a global catalog ID.

Open the complete Chapter 3 checkpoint
"""Chapter 3: inspect the Prism plan and lineage before execution."""

from domain import Order
from pub::incql import LazyFrame, Session, SessionError, inspect_lineage, inspect_plan, report_session_error


def inspect_orders(mut session: Session) -> Result[None, SessionError]:
    """Build and inspect the tutorial plan without collecting rows."""
    orders: LazyFrame[Order] = session.read_csv("tutorial_orders", "orders.csv")?
    plan = orders.limit(3)
    inspection = inspect_plan(plan.clone())
    lineage = inspect_lineage(plan)

    println(f"plan id: {inspection.plan_id}")
    println(f"authored nodes: {inspection.authored_node_count}")
    println(f"lineage edges: {len(lineage.edges)}")
    return Ok(None)


def main() -> None:
    mut session = Session.default()
    match inspect_orders(session):
        Ok(_) => println("Chapter 3: inspection completed without executing the plan")
        Err(error) => report_session_error("tutorial.chapter_03", error)

Run it from the included tutorial project:

incan run src/chapter_03.incn

A successful run prints the local plan ID, two authored nodes, eight lineage edges, and confirmation that inspection completed without executing the plan.

The exact records and current limits are documented in Local inspection.

Try it

Print each lineage edge's relationship value. For every edge you see, point back to the carrier operation that caused it. Do not interpret a missing edge as proof that no relationship exists; unsupported or conservative evidence is represented separately.

Chapter complete

You can describe what Prism knows before execution and distinguish a local PlanInspection from the backend work that has not happened yet.