{# Vendored from opportunities/detail.html. Same shell, stat strip, issue cards, and improvements catalogue. Spec 149 deltas: - breadcrumb back to /failures - eyebrow "Failure detail" (vs "Recommendation") - "Errors observed" section heading (vs "Issues found") - "Slot Wasted" stat replaces "Cost (this execution)" (failures are billed $0) - new "Failed query" code block before the improvements section so the broken SQL is always visible. #} {% extends "layout.html" %} {% block content %}
Failures {% if row.dbt_model_name %}{{ row.dbt_model_name }}{% else %}{{ row.affected_object or row.affected_table }}{% endif %}

Failure detail

{% if row.dbt_model_name %}

{{ row.dbt_model_name }}

{% else %}

{{ row.affected_object or row.affected_table }}

{% endif %}
{# Aggregate pills: how many issues + how many suggestions this object carries across the whole scan. The exact rule names live in their respective sections below. #} {% if issue_cards | length > 0 %} {{ issue_cards | length }} error categor{% if issue_cards | length != 1 %}ies{% else %}y{% endif %} {% else %} No errors {% endif %} {% if improvements | length > 0 %} {{ improvements | length }} suggestion{% if improvements | length != 1 %}s{% endif %} {% endif %} {% if row.dbt_model_name %} dbt {% endif %} {% if row.author_email %} {{ row.author_email }} {% endif %}
{% if row.affected_table %}

{{ row.affected_table }}

{% endif %}
{# Stat strip — table-level numbers from the highest-priority opportunity's representative job (issues outrank suggestions). Cost / Bytes Processed / Slot Time describe one execution of the underlying query. The cohort view exposes per-day aggregates if the user needs them. #}
{# Issues-found stat card. Lists issue rule names as plain text (one per line) so users get the failure summary up-top without scrolling. When zero issues fired (suggestion-only object), reads "—" in muted text. #}

Error categories

{% if issue_cards %}
{% for issue in issue_cards %}

{{ issue.row.opportunity_type }}

{% endfor %}
{% else %}

{% endif %}

Failed executions

{{ visible_evidence.executions if visible_evidence else "—" }}

Bytes Processed

{% if job and job.total_bytes_processed is not none %}

{{ job.total_bytes_processed | format_bytes }}

{% if job.total_bytes_billed is not none %}

billed: {{ job.total_bytes_billed | format_bytes }}

{% endif %} {% else %}

{% endif %}

Slot Wasted

{% if visible_evidence and visible_evidence.slot_wasted %}

{{ visible_evidence.slot_wasted }}

summed across every failed execution

{% else %}

{% endif %}
{# Cost trend collapsible. The full job-history cohort view lives at /jobs/{table} — link below the chart. #} {% if chart_points_payload %}
{% set chart_title = "Cost trend for this table" %} {% set chart_subtitle = "Click to expand — one point per day across the scan window. Days without executions are skipped." %} {% set chart_collapsible = true %} {% 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 %}

Errors observed

BigQuery error categories that fired across this query group. Each card lists the reason BigQuery reported plus the most recent error message it returned.

{% for issue in issue_cards %}
{{ issue.row.opportunity_type }}
{# Each column gets its own subtle sub-card so "BigQuery error" and "Try this fix" are visually distinct blocks instead of running together inside the outer card. #}

BigQuery error

{{ issue.row.explanation }}

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

{{ issue.rule_meta.description }}

{% endif %}

Try this fix

{% if improvements %}

See Available improvements below — audit found AST rewrites that may be the underlying fix.

{% else %}

No deterministic AST rewrite is available for this query. Inspect the failed SQL below and the BigQuery console for the failed job ID.

{% endif %}
{% endfor %}
{% endif %} {# Failed query block removed per user feedback — the broken SQL is already visible in the Original SQL tab of the Available improvements cards below. #} {# 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 %}

Available improvements

SQL-rewrite suggestions that apply to this object's queries. Applying them won't necessarily resolve any single issue on its own, but each reduces work the query is doing and may move the needle on cost or slot pressure.

{% for imp in improvements %}
{{ imp.display_name }} {% if imp.template_id %} deterministic rewrite {% endif %} {% if imp.occurrences and imp.occurrences > 1 %} ×{{ imp.occurrences }} {% endif %}
{% if imp.explanation %}

{{ 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 %}

All diffs are generated by deterministic templates (no LLM). Apply each one to {% if row.dbt_model_name %}your dbt model {{ row.dbt_model_name }}{% else %}the source SQL{% endif %} manually.

{% 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 %}

BigQuery query

Paste this into the BigQuery console to inspect the underlying job row.

{{ 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 %}