{# Audit's object-overview detail page. Lists EVERY active issue + EVERY available SQL-rewrite suggestion for the requested opportunity's destination_table - not just one rule's findings. The cohort view at /jobs/{table} stays as the deep-dive (cost chart, Query versions). PR / dry-run / shadow surfaces are deliberately absent - audit is read-only and never generates solutions. #} {% extends "layout.html" %} {% block content %} {% from "components/_page_header.html" import back_link, header_card %} {# Hoisted from per-section conditional blocks because Jinja {% from %} scope is the enclosing block: when issue_cards is empty (suggestion- only opportunity) the issue-section's import never fires, but later sections like Available improvements still reference the macro - produces ``'section_title' is undefined``. Hoisting once at the top of the content block makes the macro available everywhere below. #} {% from "components/_section_title.html" import section_title %} {% from "components/_sql_panel.html" import sql_panel %}
{{ back_link("/opportunities", "Issues & Suggestions") }} {% set _path_parts = (row.affected_table or '').split('.') %} {% set _dataset = _path_parts[1] if _path_parts | length >= 2 else '' %} {% set _table = _path_parts[2] if _path_parts | length >= 3 else (row.affected_table or '') %} {% set _title %}{% if _dataset %}{{ _dataset }}.{% endif %}{{ row.dbt_model_name or _table }}{% endset %} {% call header_card(_title) %} {# Build vs consumption - same classification the dashboard uses (build = writes a destination; consumption = read-only). Makes it explicit on the detail page which kind of workload this is. #} {% if row.query_workload_kind in ['build', 'consumption'] %} {{ 'Build' if row.query_workload_kind == 'build' else 'Consumption' }} {% endif %} {% if row.dbt_model_name %} dbt {% endif %} {% if row.author_email %} {{ row.author_email }} {% endif %} {# Spec 156 - origin chip in the header. Mirrors the Origin column on /opportunities. Click filters the workspace to this origin. Suppress it when it would just duplicate the green "dbt" marker above (origin 'dbt' on a dbt model) - keep it for Looker / Hex / Fivetran / etc. where it adds information. #} {% if row.origin_tool and row.origin_tool != 'ad_hoc' and not (row.origin_tool == 'dbt' and row.dbt_model_name) %} {{ row.origin_tool | replace('_', ' ') }} {% endif %} {% endcall %} {# Three-card stat strip. Each card shows the AGGREGATED figure large, with the latest execution's value on the small meta line beneath - collapses the old six-card strip into one scannable row. #} {% from "components/_stat_card.html" import stat_card %} {%- set _runs = row.execution_count or 1 -%} {%- set _runs_prefix = (_runs ~ " runs · ") if _runs > 1 else "" -%} {%- set _last_ts = latest_job.creation_time.strftime("%Y-%m-%d %H:%M UTC") if (latest_job and latest_job.creation_time) else "" -%} {%- set _agg_bytes = row.aggregated_bytes_processed or (job.total_bytes_processed if job else none) -%} {%- set _agg_slot_ms = row.aggregated_slot_time_ms or (job.total_slot_ms if job else none) -%} {%- set _cost_meta = ( _runs_prefix ~ "last " ~ ((latest_job.total_cost or 0) | float | format_usd) ~ ((" · " ~ _last_ts) if _last_ts else "") ) if latest_job else (("across " ~ _runs ~ " executions") if _runs > 1 else None) -%} {%- set _bytes_meta = ( "last " ~ (latest_job.total_bytes_processed | format_bytes) ~ ((" · billed " ~ (latest_job.total_bytes_billed | format_bytes)) if latest_job.total_bytes_billed is not none else "") ) if (latest_job and latest_job.total_bytes_processed is not none) else None -%} {%- set _slot_meta = ( "last " ~ ("%.1f" | format((latest_job.total_slot_ms or 0) / 3600000)) ~ " hrs" ~ ((" · " ~ (latest_job.duration_ms | format_duration)) if latest_job.duration_ms is not none else "") ) if (latest_job and latest_job.total_slot_ms is not none) else None -%}
{{ stat_card("Cost", row.query_cost_value | format_usd, meta=_cost_meta) }} {{ stat_card( "Bytes Processed", (_agg_bytes | format_bytes) if _agg_bytes is not none else "-", meta=_bytes_meta, accent=("brand" if _agg_bytes is not none else "slate") ) }} {{ stat_card( "Slot Time (hours)", ("%.1f" | format((_agg_slot_ms or 0) / 3600000)) if _agg_slot_ms is not none else "-", meta=_slot_meta, accent=("default" if _agg_slot_ms is not none else "slate") ) }}
{# Cost trend collapsible. "Cost trend" (not "for this table") because the same partial is used for consumption queries that have no destination table. The full job-history cohort link is passed into the partial as ``chart_history_href`` so it renders inside the collapsible's expanded body. #} {% if chart_points_payload %} {% set chart_title = "Cost trend and issues" %} {% set chart_subtitle = "One point per day across the scan window. Days without executions are skipped. Red dots mark days when this table's executions tripped a detection rule." %} {% set chart_collapsible = true %} {% set chart_history_href = "/jobs/" ~ row.affected_table %} {% include "jobs/_cost_chart.html" %} {% endif %} {# Issues found - one bordered card per issue rule that fired on this table. Each card has a 2-column Why-this-fired / Recommended- fix split, so readers can pair the cause with the fix per rule. When a rule has no template SQL diff, Recommended-fix points to the Available improvements section below rather than repeating the Why-this-fired text verbatim. When zero issues fired (suggestion-only object), this section is hidden. #} {% if issue_cards %}
{{ section_title( "Issues found", description="One card per issue that fired on this table. Each card pairs the issue's evidence (slot contention, shuffle spill, etc.) with a recommended fix.", aside=((issue_cards | length) ~ (' issue' if issue_cards | length == 1 else ' issues')) ) }}
{% for issue in issue_cards %}
{# Red issue pill - matches the red "issue count" pill in the dashboard's Top Cost Drivers table so the visual grammar is consistent across pages. #} {{ issue.row.opportunity_type | replace('_', ' ') }}
{# "Why this fired" is the single narrative on each issue card. The recommended-fix details used to live in their own section; per user feedback (v3.4) we fold the pointer to the rewrite list into this prose so the card reads as one coherent block. The full diffs / display names still live in the Available improvements section further down the page; we just don't repeat them here. #}

Why this fired

{{ issue.row.explanation }}

{% if issue.rule_meta and issue.rule_meta.description %}

{{ issue.rule_meta.description }}

{% endif %} {% if issue.template_result %}

{{ issue.template_result.explanation }}

{% if issue.diff_lines %}

Recommendations available below.

{% endif %} {% elif improvements %}

Recommendations available below.

{% else %}

No single-query SQL rewrite is available for this issue type. The fix is typically at the workload-scheduling, slot-reservation, or schema layer.

{% if layout_chip_targets %}

Partition / cluster recommendations are available - see the chips above.

{% endif %} {% endif %}
{% endfor %}
{% endif %} {# Spec 148 - Recommended physical layout. Read-only suggestion of partition + cluster keys based on how the table is queried. The partial gates on ``layout_recommendation`` so a None recommendation produces zero markup. #} {% include "opportunities/_layout_recommendation.html" %} {# Spec 154 v2 - Materialization recommendations folded into the opportunity detail page. Renders one card per audit-detected MV candidate (with generated CREATE MATERIALIZED VIEW SQL) and per BigQuery MV Recommender pass-through. The partial gates on non-empty input lists so it produces zero markup when this table has no MV signals. #} {% include "opportunities/_materialization.html" %} {# Spec 155 - Unused destination table section. Renders when the anchor opportunity_type is "unused_destination_table". The partial gates on a non-empty input list so it produces zero markup otherwise. Kept separate from the Materialization section because the question is different (should the table exist at all? vs. how should it be persisted?). #} {% include "opportunities/_unused_table.html" %} {# Available improvements - every SQL-rewrite suggestion that fired on any opportunity for this table, deduped by rule_type. Each is a deterministic rewrite (no LLM) and renders inline as its own green/red diff. #} {% if improvements %}
{{ section_title( "Available improvements", description="Deterministic SQL rewrites the audit can suggest for this table. Each card carries a green/red diff plus a rollback path.", aside=((improvements | length) ~ (' suggestion' if improvements | length == 1 else ' suggestions')) ) }}
{% for imp in improvements %}
{{ imp.display_name }} {% if imp.template_id %} deterministic rewrite {% endif %} {% if imp.occurrences and imp.occurrences > 1 %} ×{{ imp.occurrences }} {% endif %}
{# Only show the explanation prose when there's NO diff to render - the diff already conveys "what changed" visually, and the prose generated by core's templates duplicates the column / CTE names plus a boilerplate "What changed" paragraph that adds nothing. #} {% if imp.explanation and not (imp.diff_lines or imp.before_content) %}

{{ imp.explanation }}

{% endif %} {% if imp.diff_lines or imp.before_content %}
{% if imp.after_content %} {% endif %}
{% if imp.diff_lines %} {% set diff_lines = imp.diff_lines %} {% set file_path = imp.template_id %} {% include "components/code_diff.html" %} {% else %}

No diff available - template did not produce a change.

{% endif %}
{% if imp.after_content %} {% endif %}
{% endif %} {% if imp.rollback %}
Rollback instructions

{{ imp.rollback }}

{% endif %}
{% endfor %}
{% endif %} {# Query fallback - when no SQL-rewrite suggestions fired on this opportunity, the user still needs to see the underlying query so they can manually inspect what's running. Suggestion cards already include an "Original SQL" tab; this block is the fallback path when ``improvements`` is empty. Renders only when we have a representative job with a query body. #} {% if not improvements and job and job.query %}
{{ section_title( "Query", description="The latest execution of this query. No deterministic SQL-rewrite suggestion is available for this opportunity - the fix is at the workload-scheduling or schema layer." ) }}
{% for line in job.query.split('\n') %}{{ loop.index }}{{ line }}
{% endfor %}
{% endif %} {# Evidence + BigQuery query lookup - two side-by-side cards on >=lg, stacked on smaller screens. Each card collapses independently. The right-hand card renders the ``INFORMATION_SCHEMA.JOBS_BY_PROJECT`` SELECT pre-filtered by job_id so the user can paste it into the BigQuery console and inspect the row themselves. Evidence + lookup come from the representative opportunity (highest-priority for this table). #} {% if visible_evidence or job_lookup_sql %}
{% if visible_evidence %}

Evidence

{% for key, value in visible_evidence.items() %}
{{ key }}
{% if value is mapping or (value is iterable and value is not string) %} {{ value | tojson }} {% else %} {{ value }} {% endif %}
{% endfor %}
{% endif %} {% if job_lookup_sql %} {{ sql_panel("job-lookup-sql", "BigQuery query", job_lookup_sql) }} {% endif %}
{% endif %}
{# Generic tab toggler - picks up every ``[data-tab]`` / ``[data-tab-pane]`` pair inside an ancestor with ``[data-active-tab]``. Same script as the cohort page so suggestion cards' Diff / Original SQL tabs work without coupling to the class name. #} {% endblock %}