From b2d744fe423dee07409cb9af4fd1c5197f9f4d71 Mon Sep 17 00:00:00 2001 From: Lucio Lelii Date: Thu, 3 Sep 2026 22:10:16 +0200 Subject: [PATCH] Make the bias experiment reachable, and say why when it is not The Bias impact tab is empty because no experiment has ever run - zero rows in bias_impact_report_entity - and nothing in the UI said how one is started. The empty state now explains what a report is, says how many nodes carry a probe that can be activated on this run, and offers the action. When something is in the way it states that instead: a subflow cannot be a baseline, an unfinished run cannot be compared against a rerun, a flow with no activatable probe has nothing to measure. "Create biased rerun" no longer returns silently when no node qualifies - a button that does nothing and explains nothing is indistinguishable from a broken one. It now names the reason. The per-node measure control is shown on interactive blocks instead of hidden. ChatInteraction cannot be replayed in isolation, so the isolated experiment is genuinely unavailable there - but hiding the control made an annotated node look identical to an unannotated one. It is rendered disabled, and the tooltip points at the full-flow route that does work. That is a rule of the domain, worth stating rather than concealing. Splitting the node scan out of biasRerunCandidates keeps this free: the count is computed from the flow snapshot, while only the capability check needs the network. 506 frontend tests green; each new assertion fails when its behaviour is undone. Initial bundle now 2.86 kB over budget, up from 2.21 kB - reported, not raised. Co-Authored-By: Claude Opus 5 (1M context) --- .../bias-impact-report-list.css | 27 +++++++- .../bias-impact-report-list.html | 20 +++++- .../bias-impact-report-list.spec.ts | 40 +++++++++++ .../bias-impact-report-list.ts | 9 ++- .../task-step-node/task-step-node.spec.ts | 66 +++++++++++++++++++ .../nodes/task-step-node/task-step-node.ts | 25 +++++-- .../task-execution-viewer.html | 6 +- .../task-execution-viewer.ts | 49 +++++++++++++- 8 files changed, 231 insertions(+), 11 deletions(-) diff --git a/src/app/shared/bias-impact-report-list/bias-impact-report-list.css b/src/app/shared/bias-impact-report-list/bias-impact-report-list.css index e027d15..0d5ecac 100644 --- a/src/app/shared/bias-impact-report-list/bias-impact-report-list.css +++ b/src/app/shared/bias-impact-report-list/bias-impact-report-list.css @@ -2,7 +2,32 @@ .bias-report-list__progress { background: #eff6ff; border-left: 3px solid #2563eb; color: #1e3a8a; margin: 0; padding: .6rem .7rem; font-size: .84rem; } .bias-report-list__error { background: #fff1f2; border-left: 3px solid #e11d48; color: #9f1239; margin: 0; padding: .6rem .7rem; font-size: .84rem; } .bias-report-list__error-row { align-items: center; display: flex; gap: .6rem; justify-content: space-between; } -.bias-report-list__empty { color: #64748b; font-size: .84rem; margin: 0; padding: .5rem; } +/* An empty tab that only said "none yet" left the user with no idea how one is produced. */ +.bias-report-list__empty { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: .5rem; + color: #64748b; + font-size: .84rem; + padding: .5rem; +} + +.bias-report-list__empty p { margin: 0; } + +.bias-report-list__empty-lead { color: #334155; font-weight: 600; } + +.bias-report-list__empty-body { line-height: 1.45; } + +/* The precondition that is in the way, stated instead of left to be guessed from a dead button. */ +.bias-report-list__empty-blocked { + border-left: 3px solid #f59e0b; + background: #fffbeb; + border-radius: 4px; + padding: .4rem .55rem; + color: #92400e; + line-height: 1.45; +} .bias-report-list__row { align-items: center; diff --git a/src/app/shared/bias-impact-report-list/bias-impact-report-list.html b/src/app/shared/bias-impact-report-list/bias-impact-report-list.html index 988c330..bb9125b 100644 --- a/src/app/shared/bias-impact-report-list/bias-impact-report-list.html +++ b/src/app/shared/bias-impact-report-list/bias-impact-report-list.html @@ -21,7 +21,25 @@ } @else if (!reports().length) { -

No bias impact reports for this execution yet.

+
+

No bias impact reports for this run yet.

+

+ A report compares this run against the same run with its bias or mitigation probes turned + on, and shows which node outputs it changed. Reports appear here once you produce one. +

+ @if (blockedReason(); as reason) { +

{{ reason }}

+ } @else { +

+ {{ annotatedNodeCount() }} + {{ annotatedNodeCount() === 1 ? 'node carries a probe' : 'nodes carry a probe' }} + that can be activated on this run. +

+ + } +
} @else { @for (report of reports(); track report.id) {