# Story 6.2: Inline Evidence Expansion

## Story

**As a** data steward,
**I want** to expand a prediction row to see the full evidence trail without leaving the list view,
**So that** I can understand exactly why a category was suggested and decide in seconds whether to trust it.

## Status

done

## Acceptance Criteria

All ACs met.

## Tasks / Subtasks

- [x] **Task 1: `EvidenceService::getEvidenceForPrediction()`** — Updated to also query `akeneo_workflow` by `prediction_id` (most recent record DESC). Returns `akeneo_workflow: array|null` alongside existing `evidence`, `attributes`, `total_weight` keys.

- [x] **Task 2: Evidence expansion script** — Added as a second IIFE `<script>` block in `src/Views/predictions/index.php`.
  - Delegated click handler on `#predictions-container` targets `.prediction-row`.
  - Click on `td:first-child` (checkbox cell), `button`, or `a` is ignored.
  - First click: inserts `<tr class="evidence-panel-row" data-evidence-for="{id}">` with `colspan=8` immediately after the prediction row; fetches `/api/predictions/{id}/evidence`.
  - Subsequent clicks: toggle panel row `display` and `.evidence-open` class on the prediction row.
  - Multiple rows can be expanded simultaneously (no auto-collapse).
  - Evidence HTML is cached in a closure-local JS object keyed by prediction ID; re-expanding a row serves from cache without re-fetching.
  - On fetch failure: error message replaces loading placeholder; row remains expanded (panel row stays in DOM).

- [x] **Task 3: Evidence panel HTML builder** (`buildEvidenceHtml`)
  - Heading: "Why this category was suggested"
  - Evidence items ordered by weight DESC (server already returns them that way): `source_label` (bold), `evidence_value` (plain text), `weight_pct`% of confidence.
  - Items with `source_label === 'fallback'` (case-insensitive): `.evidence-item-fallback` CSS class (opacity 0.65) + note "Limited data available — prediction confidence is low".
  - Summary line: "Based on X evidence signals"
  - Missing data section: filters `attributes` where `attribute_value` is null/empty; renders list labeled "These attributes are missing and could improve confidence if provided"; hidden when no missing attributes exist.
  - Akeneo workflow status: shown as a badge when `data.akeneo_workflow.workflow_status` is present; fetched from `akeneo_workflow` table (not products.status).

- [x] **Task 4: CSS** — Added to `public/assets/css/styles.css`:
  - `.evidence-panel-row > td` — no padding, light gray background, no top border.
  - `.evidence-panel` — top border 2px primary blue, bottom border, max-width 760px.
  - `.evidence-item`, `.evidence-item-fallback`, `.evidence-value`, `.missing-data-section`.
  - `.prediction-row.evidence-open` — light blue row background to indicate expanded state.

- [x] **Task 5: Cache invalidation** — Evidence expansion IIFE wraps `window.PredictionsQueue.removeRow` to delete the cache entry and remove any open panel row when a prediction is removed from the queue (called by Story 6.3).

## Dev Notes

### Evidence API unchanged

`PredictionController::evidenceApi()` and the `GET /api/predictions/{id}/evidence` route are unchanged. Only the `EvidenceService` return value is extended with `akeneo_workflow`.

### Panel row and AJAX rebuilds

The panel rows are inserted into the table `<tbody>` via `insertAdjacentElement('afterend', tr)`. When the AJAX tab-switch in Story 6.1 runs `container.innerHTML = ...`, all panel rows are destroyed. The `evidenceCache` (closure variable, not DOM) persists across tab switches, so re-expanding a prediction that was visible before the switch still serves from cache. Cache entries are never stale within a page session — the evidence data for a prediction does not change between tab switches.

### File list

**Modified files:** `src/Services/EvidenceService.php` (akeneo_workflow query added), `src/Views/predictions/index.php` (evidence expansion script block added), `public/assets/css/styles.css` (evidence panel styles added)
