{# 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) %} {% if row.dbt_model_name %} dbt {% endif %} {% if row.author_email %} {{ row.author_email }} {% endif %} {% endcall %} {# Six-card stat strip - aggregated lifetime metrics on the left half, last-execution snapshot on the right half. Lives outside the ``ui-surface`` header so the cards read as a standalone strip (mirrors the dashboard's cost-summary row). ``grid-cols-6`` isn't in the pre-compiled Tailwind bundle (same constraint as ``_cost_summary.html``), so we inline the 6-column rule below the xl breakpoint and rely on Tailwind's built-in 1/2/3 cols at smaller widths. #} {% from "components/_stat_card.html" import stat_card %} {%- set _exec_meta = ("across " ~ row.execution_count ~ " executions") if (row.execution_count and row.execution_count > 1) else None -%}
{{ stat_card("Cost (aggregated)", row.query_cost_value | format_usd, meta=_exec_meta) }} {% if row.aggregated_bytes_processed %} {{ stat_card("Bytes Processed (aggregated)", row.aggregated_bytes_processed | format_bytes, meta=_exec_meta, accent="brand") }} {% elif job and job.total_bytes_processed is not none %} {{ stat_card("Bytes Processed (aggregated)", job.total_bytes_processed | format_bytes, accent="brand") }} {% else %} {{ stat_card("Bytes Processed (aggregated)", "-", accent="slate") }} {% endif %} {% if row.aggregated_slot_time_ms %} {{ stat_card("Slot Time (aggregated, hours)", "%.1f" | format((row.aggregated_slot_time_ms or 0) / 3600000), meta=_exec_meta) }} {% elif job and job.total_slot_ms is not none %} {{ stat_card("Slot Time (aggregated, hours)", "%.1f" | format((job.total_slot_ms or 0) / 3600000)) }} {% else %} {{ stat_card("Slot Time (aggregated, hours)", "-", accent="slate") }} {% endif %} {# Last-execution trio - same three metrics for the most-recent cached run so the user can compare the freshest point against the aggregated lifetime view to its left. Hidden when no cached execution exists for the affected_table. #} {% if latest_job %} {{ stat_card( "Last Execution Cost", (latest_job.total_cost or 0) | float | format_usd, meta=latest_job.creation_time.strftime("%Y-%m-%d %H:%M UTC") if latest_job.creation_time else None ) }} {% if latest_job.total_bytes_processed is not none %} {{ stat_card( "Last Execution Bytes", latest_job.total_bytes_processed | format_bytes, meta=("billed: " ~ (latest_job.total_bytes_billed | format_bytes)) if latest_job.total_bytes_billed is not none else None, accent="brand" ) }} {% else %} {{ stat_card("Last Execution Bytes", "-", accent="slate") }} {% endif %} {% if latest_job.total_slot_ms is not none %} {{ stat_card( "Last Execution Slot (hours)", "%.1f" | format((latest_job.total_slot_ms or 0) / 3600000), meta=("duration: " ~ (latest_job.duration_ms | format_duration)) if latest_job.duration_ms is not none else None ) }} {% else %} {{ stat_card("Last Execution Slot (hours)", "-", accent="slate") }} {% endif %} {% endif %}
{# 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 + Recommended-fix stacked vertically inside one issue card. Previous layout used a two-column grid with tinted sub-card backgrounds, which made the card feel like two boxes side-by-side; consolidating into one column with a thin divider between the two sections reads as a single narrative ("here's what happened, here's what to do"). #}

Why this fired

{{ issue.row.explanation }}

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

{{ issue.rule_meta.description }}

{% endif %}

Recommended fix

{% if issue.template_result %}

{{ issue.template_result.explanation }}

{% if issue.diff_lines %}

SQL diff in Available improvements below.

{% endif %} {% elif improvements %} {# Audit has SQL-rewrite improvements queued for this table. List them by display name so the user sees what's available without scrolling. SQL rewrites are deterministic byte-for- byte changes but MAY NOT fully resolve every issue type - slot contention, for example, often needs scheduling changes or slot reservation alongside any rewrite. #}

Available rewrites queued in Available improvements below:

    {% for imp in improvements %}
  • {{ imp.display_name }}
  • {% endfor %}

These rewrites reduce work touched by the query and may help, but won't always fully resolve {{ issue.row.opportunity_type | replace('_', ' ') }} on their own - the underlying fix is often at the schema (partition / cluster) or scheduling layer.

{% if layout_chip_targets %}

For partition / cluster recommendations on this table (typically higher-confidence for scan-volume issues), see the chips above.

{% endif %} {% 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" %} {# 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 %}