Skip to content

dashboard: surface audit data in run details with progressive disclosure#42269

Merged
pelikhan merged 4 commits into
mainfrom
copilot/update-run-details-view
Jun 29, 2026
Merged

dashboard: surface audit data in run details with progressive disclosure#42269
pelikhan merged 4 commits into
mainfrom
copilot/update-run-details-view

Conversation

Copilot AI commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

The Run details tab showed only summary metrics from logs. This adds on-demand gh aw audit integration so users can drill into structured audit output for any selected run without leaving the dashboard.

Backend

  • dashboard-data.mjsgetAudit(runId): calls gh aw audit <id> --json, parses and caches result per run ID
  • extension.mjs/api/audit?run_id= endpoint + auditRun canvas action (accepts run_id: string); system message updated to document the action

Frontend

  • app.jsauditData/loadingAudit/errorAudit state; loadAudit(), clearAudit(), auditHasFindings(), auditSeverityClass(), auditPriorityClass() methods; selectRun() clears stale audit on navigation

  • index.html — Run details tab gains a Run Audit button below the existing metric cards; results render as <details>/<summary> sections:

    Section Default Content
    Overview open branch, event, created, duration, experiment, run URL
    Key Findings open if non-empty severity + category badges, title, description, impact
    Recommendations collapsed priority, action, reason, example
    Jobs collapsed name, conclusion, duration
    Tool Usage collapsed grid: calls, max output, max duration
    Errors & Warnings collapsed type, message, file:line
  • styles.css — tool usage grid layout; <details> native marker suppressed for consistent arrow

Copilot AI and others added 2 commits June 29, 2026 14:59
…sure

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…gnment, better error message

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title Update run details view with audit integration and progressive disclosure dashboard: surface audit data in run details with progressive disclosure Jun 29, 2026
Copilot AI requested a review from pelikhan June 29, 2026 15:01
@pelikhan pelikhan marked this pull request as ready for review June 29, 2026 15:05
Copilot AI review requested due to automatic review settings June 29, 2026 15:05
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR does not have the 'implementation' label and has ≤100 new lines of code in business logic directories (default_business_additions=0).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the agentic workflows dashboard “Run details” view by adding an on-demand gh aw audit <run_id> --json integration, allowing users to drill into structured audit output with progressive disclosure directly in the canvas UI.

Changes:

  • Added backend audit retrieval (getAudit(runId)) with per-run caching and exposed it via a new /api/audit?run_id= endpoint plus an auditRun canvas action.
  • Added frontend audit state + “Run Audit”/“Clear audit” controls and rendered audit results as <details>/<summary> sections (overview, findings, recommendations, jobs, tool usage, errors/warnings).
  • Added CSS for tool usage grid layout and standardized disclosure marker styling.
Show a summary per file
File Description
.github/extensions/agentic-workflows-dashboard/dashboard-data.mjs Adds getAudit(runId) that runs gh aw audit --json, parses output, and caches by run ID.
.github/extensions/agentic-workflows-dashboard/extension.mjs Exposes /api/audit endpoint and adds auditRun canvas action wiring/documentation.
.github/extensions/agentic-workflows-dashboard/web/app.js Introduces audit UI state and fetch logic (loadAudit/clearAudit) plus helpers for rendering badges/sections.
.github/extensions/agentic-workflows-dashboard/web/index.html Adds “Run Audit” UI and renders structured audit sections using progressive disclosure.
.github/extensions/agentic-workflows-dashboard/web/styles.css Adds tool usage grid styling and suppresses native <details> marker for consistent disclosure UI.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 5/5 changed files
  • Comments generated: 5
  • Review effort level: Low

Comment on lines 271 to 275
selectRun(runId) {
this.selectedRun = this.runs.find(run => run.run_id === runId) ?? null;
this.auditData = null;
this.errorAudit = "";
},
Comment on lines +282 to +298
async loadAudit() {
if (!this.selectedRun) return;
this.loadingAudit = true;
this.errorAudit = "";
this.auditData = null;
try {
const params = new URLSearchParams({ run_id: String(this.selectedRun.run_id) });
const resp = await fetch(`/api/audit?${params.toString()}`);
const data = await resp.json();
if (!resp.ok) throw new Error(data.error ?? `HTTP ${resp.status}`);
this.auditData = data;
} catch (error) {
this.errorAudit = `Audit failed: ${error.message}`;
} finally {
this.loadingAudit = false;
}
},
properties: { run_id: { type: "string", description: "The workflow run ID to audit (numeric string)." } },
additionalProperties: false,
},
handler: async ctx => dataAccess.getAudit(String(ctx.input?.run_id ?? "")),
Comment on lines +62 to +68
details > summary {
list-style: none;
}

details > summary::-webkit-details-marker {
display: none;
}
Comment thread .github/extensions/agentic-workflows-dashboard/web/index.html Outdated
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

No test files were added or modified in this PR. Test Quality Sentinel skipped. PR #42269 ('dashboard: surface audit data in run details with progressive disclosure') only modifies dashboard extension files: dashboard-data.mjs, extension.mjs, web/app.js, web/index.html, web/styles.css — no Go or JavaScript test files.

@github-actions github-actions Bot mentioned this pull request Jun 29, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: dashboard audit surface

Good progressive-disclosure design and clean separation between backend (getAudit//api/audit) and frontend state. Five issues found — one correctness bug, one security concern, and three lower-priority suggestions.

Blocking

# File Issue
1 app.js:271 Race condition — switching runs while audit loads shows wrong run's data
2 index.html:217 Unvalidated URL from audit JSON bound to :href (javascript: XSS risk)

Non-blocking suggestions

# File Issue
3 app.js:290 resp.json() called before resp.ok check — confusing errors on non-JSON server responses
4 index.html:181 btn-danger (red) for a reversible "Clear audit" action
5 styles.css:62 Global details > summary selector; also redundant with inline list-style:none

Inline comments added for all five.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 55.8 AIC · ⌖ 9.95 AIC · ⊞ 4.9K

selectRun(runId) {
this.selectedRun = this.runs.find(run => run.run_id === runId) ?? null;
this.auditData = null;
this.errorAudit = "";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Race condition: stale audit state bleeds into newly selected run.

selectRun clears auditData and errorAudit but leaves loadingAudit untouched. If the user clicks Run Audit on Run A, then switches to Run B before the fetch resolves:

  1. Run B UI shows "Running audit..." (stale loadingAudit = true)
  2. When Run A's fetch completes, this.auditData = data overwrites Run B's state with Run A's audit results

Suggested fix:

selectRun(runId) {
  this.selectedRun = this.runs.find(run => run.run_id === runId) ?? null;
  this.auditData = null;
  this.errorAudit = "";
  this.loadingAudit = false; // reset stale loading state
},

And in loadAudit, guard the write with a snapshot check:

const targetRunId = this.selectedRun.run_id;
// ... await fetch ...
if (this.selectedRun?.run_id === targetRunId) {
  this.auditData = data;
}

@copilot please address this.

const params = new URLSearchParams({ run_id: String(this.selectedRun.run_id) });
const resp = await fetch(`/api/audit?${params.toString()}`);
const data = await resp.json();
if (!resp.ok) throw new Error(data.error ?? `HTTP ${resp.status}`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resp.json() is called before resp.ok is checked — if the server ever returns a non-JSON error body (e.g. an unexpected crash outside the try/catch in extension.mjs), this will throw a SyntaxError and the user sees "Audit failed: Unexpected token..." instead of a meaningful message.

Safer pattern:

const resp = await fetch(`/api/audit?${params.toString()}`);
if (!resp.ok) {
  let msg = `HTTP ${resp.status}`;
  try { msg = (await resp.json()).error ?? msg; } catch { /* ignore parse error */ }
  throw new Error(msg);
}
this.auditData = await resp.json();

@copilot please address this.

<div class="flex-1">
<div class="text-small color-fg-muted">URL</div>
<div class="text-small">
<a :href="auditData?.overview?.url ?? '#'" target="_blank" rel="noreferrer" x-show="auditData?.overview?.url" x-text="'View run ↗'"></a>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unvalidated URL from audit JSON used in :href — Alpine's :href binding does not sanitize URLs, so a (redacted) scheme in auditData.overview.urlwould execute when clicked. Whilegh aw audit` output is local, audit data ultimately reflects workflow run metadata which can be influenced by repository content.

Add a URL scheme guard before binding:

auditRunUrl() {
  const url = this.auditData?.overview?.url ?? '';
  return /^https?:\/\//i.test(url) ? url : '#';
},

Then use :href="auditRunUrl()" and :show="auditRunUrl() !== '#'" in the template.

@copilot please address this.

<div class="d-flex flex-items-center gap-2 mb-2">
<button class="btn btn-sm" @click="loadAudit()" :disabled="loadingAudit" x-show="!auditData && !loadingAudit">
Run Audit
</button>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btn-danger (red) for a reversible action — "Clear audit" only clears in-memory display state; the user can re-run the audit at any time. Using btn-danger implies a destructive or irreversible operation (matching GitHub's own Primer convention). A plain btn btn-sm or btn-outline btn-sm would match the action's low-risk nature and avoids alarming the user.

@copilot please address this.

z-index: 1;
}

details > summary {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Global details > summary selector — This suppresses the native disclosure triangle on all <details> elements in the app, not just audit ones. Currently there are no other <details> usages, but this will silently affect any future additions.

Note also that each <summary> in index.html already has style="list-style:none" inline, making the list-style: none rule here redundant. The ::-webkit-details-marker rule is still useful for old WebKit.

Consider scoping to the audit container:

.awd-audit details > summary { list-style: none; }
.awd-audit details > summary::-webkit-details-marker { display: none; }

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /grill-with-docs, /tdd, and /zoom-out — requesting changes on 6 issues. The core feature is solid and well-structured; the asks are targeted polish before merge.

📋 Key Themes & Highlights

Issues to address

  • UX correctness — Hardcoded chevron never flips on collapse (all 6 <summary> elements) — simple CSS fix
  • Architecture scopedetails > summary CSS rule is page-global instead of scoped to the audit panel
  • Test coverage — 4 new pure helper methods and the loadAudit error path are untested
  • Error contextrunGhAw failure inside getAudit bubbles up without the run ID that caused it
  • Fallback correctnessauditSeverityClass unknown-severity fallback returns Label--accent (blue) instead of neutral Label--secondary
  • UX consistency — Empty-state treatment differs between sections: Findings/Recommendations show "No X" while Jobs/Tool Usage/Errors hide entirely

Positive highlights

  • ✅ Clean layering: getAudit in data layer → endpoint in server → state + methods in Alpine → markup in HTML
  • ✅ JSON parse error message includes a truncated snippet — great diagnostics
  • selectRun() clears stale audit state on navigation — no stale-data bugs
  • loadingAudit reset in finally — correct async state management
  • ✅ Canvas action schema is well-typed with additionalProperties: false
  • ✅ The progressive-disclosure structure (Overview open, rest collapsed) is thoughtful UX

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 68.6 AIC · ⌖ 9.07 AIC · ⊞ 6.6K
Comment /matt to run again

<div x-show="auditData">
<!-- Overview -->
<details class="mb-2" open>
<summary class="btn-link text-bold color-fg-default mb-1" style="cursor:pointer;list-style:none">▾ Overview</summary>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/grill-with-docs] The chevron is hardcoded text and never flips — users who collapse a section will still see ("open" indicator), making the toggle state ambiguous.

💡 Suggested CSS-driven fix

Remove the prefix from every <summary> element and drive the indicator in CSS:

/* styles.css — replaces hardcoded ▾ in markup */
.awd-audit-section details > summary::before {
  content: "▾";
  display: inline-block;
  margin-right: 4px;
  transition: transform 0.15s ease;
}
.awd-audit-section details:not([open]) > summary::before {
  transform: rotate(-90deg);
}

This keeps the visual state in sync with the <details> open/closed attribute automatically, with no JS needed.

@copilot please address this.

z-index: 1;
}

details > summary {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/zoom-out] details > summary is a page-global rule — it will silently suppress native markers on any <details> element added elsewhere in the dashboard in the future, not just the audit panel ones.

💡 Suggested fix — scope the rule

Wrap the audit section in a container with a scoped class and target that instead:

<!-- index.html: add class to the audit wrapper -->
<div class="border-top pt-3 awd-audit-section">
/* styles.css */
.awd-audit-section details > summary {
  list-style: none;
}
.awd-audit-section details > summary::-webkit-details-marker {
  display: none;
}

This is the same selector scope used by the existing .awd-tool-usage-header / .awd-tool-usage-row classes — consistent and contained.

@copilot please address this.

this.setActiveTab("details");
},

async loadAudit() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] loadAudit(), auditHasFindings(), auditSeverityClass(), and auditPriorityClass() are all untested. The severity/priority class mapping is particularly prone to silent failures if the audit API returns an unexpected value.

💡 What to test

The pure helpers are easy to unit test without a browser:

// auditSeverityClass
it('returns danger class for critical severity', () => {
  expect(app.auditSeverityClass('critical')).toBe('Label Label--danger');
});
it('returns secondary for unknown severity', () => {
  // catches the fallback 'Label--accent' issue (see related comment)
  expect(app.auditSeverityClass('info')).toBe('Label Label--secondary');
});

// loadAudit error path
it('sets errorAudit on HTTP error', async () => {
  global.fetch = vi.fn().mockResolvedValue({ ok: false, status: 503, json: async () => ({}) });
  await app.loadAudit();
  expect(app.errorAudit).toMatch(/503/);
  expect(app.loadingAudit).toBe(false);
});

The existing test file for app.js (if one exists) is the right place to add these. If there is no test file yet, this PR is a good time to start one.

@copilot please address this.

const hit = getCached(key);
if (hit) return hit;

const raw = await runGhAw(["audit", String(runId), "--json"]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] If runGhAw throws (e.g., the CLI exits non-zero), the raw error propagates without identifying which run was being audited. Only the JSON parse failure path adds run ID context — the process failure path should too.

💡 Suggested fix
async function getAudit(runId) {
  if (!runId) return null;
  const key = `audit:${runId}`;
  const hit = getCached(key);
  if (hit) return hit;

  let raw;
  try {
    raw = await runGhAw(["audit", String(runId), "--json"]);
  } catch (err) {
    throw new Error(`gh aw audit failed for run ${runId}: ${err.stderr ?? err.message}`);
  }

  let data;
  try {
    data = JSON.parse(raw);
  } catch (error) {
    // ... existing snippet logic
  }
  setCached(key, data);
  return data;
}

This makes error messages actionable in the dashboard's errorAudit state and in server logs.

@copilot please address this.

if (severity === "critical" || severity === "high") return "Label Label--danger";
if (severity === "medium") return "Label Label--attention";
if (severity === "low") return "Label Label--secondary";
return "Label Label--accent";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/grill-with-docs] The fallback "Label Label--accent" fires for any unrecognized severity value and renders a blue accent badge, which can be misread as "informational" rather than "unknown". A neutral secondary badge is safer as a catch-all.

💡 Suggested fix
auditSeverityClass(severity) {
  if (severity === "critical" || severity === "high") return "Label Label--danger";
  if (severity === "medium") return "Label Label--attention";
  if (severity === "low") return "Label Label--secondary";
  return "Label Label--secondary"; // unknown/undefined → neutral, not accent
},

If info or other levels are intentional additions from gh aw audit --json, document the full set of valid severity values in a JSDoc comment here so reviewers can verify the mapping is complete.

@copilot please address this.

</details>

<!-- Jobs -->
<details class="mb-2" x-show="(auditData?.jobs ?? []).length > 0">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/grill-with-docs] Jobs, Tool Usage, and Errors & Warnings use x-show to hide entirely when empty, while Key Findings and Recommendations show explicit "No X" messages. This inconsistency leaves users wondering whether those sections returned empty data or simply were not included in the audit response.

💡 Suggested approach — pick one pattern and apply it consistently

Option A (preferred — matches Findings/Recommendations): always show the section header and add an empty-state message:

<!-- Jobs: remove x-show from <details>, add empty state inside -->
<details class="mb-2">
  <summary ...>▾ Jobs <span class="Counter" x-text="..."></span></summary>
  <div class="Box mt-1" x-show="(auditData?.jobs ?? []).length > 0">
    <!-- existing template loop -->
  </div>
  <div class="color-fg-muted text-small mt-1" x-show="(auditData?.jobs ?? []).length === 0">No jobs.</div>
</details>

Repeat for Tool Usage and Errors & Warnings. This makes it clear when a section has data vs when the audit found nothing.

Option B: hide all empty sections with x-show (simpler, but loses the "no findings" signal). Remove the "No key findings" and "No recommendations" empty-state divs.

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — Two correctness bugs must be fixed before merge; three medium issues also filed.

### Blocking issues (must fix)

1. Stuck loadingAudit spinner on navigationselectRun() resets auditData and errorAudit but not loadingAudit. If the user selects a different run while an audit fetch is in-flight, the new run's details panel shows a perpetual "Running audit..." indicator with no way to dismiss it. See inline comment on selectRun.

2. Stale audit data race conditionloadAudit() captures this.selectedRun.run_id at call time but writes results back via this.auditData after await. If the user switches runs while the fetch is pending, the old result overwrites the new run's state. See inline comment on the loadAudit() body.

### Medium issues (filed inline)
  • resp.json() before resp.ok check — non-JSON error bodies (e.g., HTML 500 page) surface as a confusing SyntaxError instead of the HTTP status code. Defensive JSON parse inside its own try/catch fixes this.
  • Unsanitized :href from audit URL — Alpine's dynamic href binding accepts any URL scheme; a `(redacted) URI in audit output would execute on click. A one-line scheme regex guard eliminates the class.
  • auditRun canvas handler returns null silently for empty/invalid run_id — schema marks run_id required but the handler short-circuits to null rather than throwing an actionable error.
### Non-blocking observations
  • CSS: Firefox still shows the native disclosure marker alongside the custom because ::marker is not suppressed — only ::-webkit-details-marker. Adding summary::marker { display: none } or list-style: none at the ::marker level fixes this cross-browser.
  • The hardcoded arrow in every <summary> does not toggle to when the section is open, giving no visual open/closed state feedback since the native arrow is suppressed.

🔎 Code quality review by PR Code Quality Reviewer · 188 AIC · ⌖ 12.1 AIC · ⊞ 5.2K
Comment /review to run again

Comments that could not be inline-anchored

.github/extensions/agentic-workflows-dashboard/web/app.js:291

resp.json() can throw before resp.ok is checked, masking the HTTP error status: when the server returns a non-JSON body (e.g., an HTML 500 from an unexpected crash), resp.json() throws a SyntaxError and the catch block sets errorAudit to &quot;Audit failed: Unexpected token &lt;&quot; — losing the actual HTTP status entirely.

<details>
<summary>💡 Suggested fix</summary>

Parse JSON defensively so the HTTP status is always surfaced:

const resp = await fetch(`/api/audit?${params.toS…

</details>

<details><summary>.github/extensions/agentic-workflows-dashboard/web/index.html:217</summary>

**Alpine&#39;s `:href` binding does not sanitize URL schemes**: `auditData?.overview?.url` is bound directly to `href` without validating the scheme. If the audit CLI output ever contains a `(redacted) or `(redacted) URI in the `url` field (e.g., due to malformed audit data), clicking the link executes arbitrary JavaScript in the dashboard context.

&lt;details&gt;
&lt;summary&gt;💡 Suggested fix&lt;/summary&gt;

Add a scheme guard  either inline or as a helper method:

```js
// in app.js
safeAuditUrl() {
  const u…

</details>

<details><summary>.github/extensions/agentic-workflows-dashboard/web/app.js:180</summary>

**`fetchRuns()` bypasses `selectRun()`, leaving stale audit data visible for the wrong run**: the run-refresh path re-assigns `this.selectedRun` in-place (e.g., by finding the same run in the updated list or falling back to `runs[0]`) without going through `selectRun()`, which is the only place that clears `auditData` and `errorAudit`. Concretely: open run A&#39;s details with audit loaded, hit Refresh while run A drops off the list, the fallback picks run B — but the audit panel still shows run A&#39;…

</details>

<details><summary>.github/extensions/agentic-workflows-dashboard/dashboard-data.mjs:212</summary>

**CLI error payload (exit 0, `{&quot;error&quot;:&quot;...&quot;}`) passes JSON parsing, gets cached, and is returned as HTTP 200 with no error surfaced in the UI**: `setCached(key, data)` runs whenever `JSON.parse` succeeds, regardless of whether the payload contains an application-level error. If `gh aw audit` exits with code 0 but emits `{&quot;error&quot;:&quot;run not found&quot;}`, the response is cached for the full TTL and served as a 200 response. The client&#39;s `if (!resp.ok)` guard never fires, so `this.auditData` is set to …

</details>

<details><summary>.github/extensions/agentic-workflows-dashboard/dashboard-data.mjs:202</summary>

**`runId` is passed as a positional argv entry before any `--` end-of-options sentinel, so a value like `&quot;--help&quot;` or `&quot;--timeout=0&quot;` is interpreted as a CLI flag, not a run ID**: `runGhAw([&quot;audit&quot;, String(runId), &quot;--json&quot;])` places the run ID at `argv[1]`, before the double-dash that would terminate option parsing. `execFile` prevents shell injection, but flag injection via argv is still possible. Via the canvas `auditRun` action, an LLM agent can supply any string as `run_id`.

&lt;details&gt;
&lt;sum…

</details>

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

…alidation, CSS marker, noopener

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

All review comments addressed in commit fix: address review comments — race condition, stuck spinner, input validation, CSS marker, noopener:

  • app.jsselectRun() now resets loadingAudit = false to prevent a stuck spinner when switching runs mid-flight; loadAudit() captures requestedRunId at request start and guards all state writes against stale responses (race condition fix)
  • extension.mjsauditRun handler validates run_id is a non-empty numeric string before forwarding to getAudit(), throwing a clear error otherwise
  • styles.css — added details > summary::marker { display: none } alongside the existing WebKit rule for cross-browser disclosure marker suppression
  • index.htmlrel="noreferrer" updated to rel="noopener noreferrer" on the target="_blank" run URL link

Local validation (typecheck + tests) passes. CI will need a human re-trigger to confirm on the updated HEAD.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

Copilot AI commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

All code changes are already in place from the previous pass (commit 15b3b30). Local validation is green (typecheck + 14 tests pass, make fmt reports no changes). No new file changes were needed.

  • Reviews — All 4 unresolved threads were addressed in the previous commit: race condition fix, stuck spinner reset, run_id validation, ::marker CSS rule. The noopener thread is already marked resolved.
  • Checks (local)typecheck, vitest (14 tests), and make fmt all pass.
  • Checks (CI) — Stale after agent push; needs human re-trigger. GraphQL returns 403 so prior CI status is unverifiable from this agent.
  • Mergeable — GraphQL returns 403; no conflicts detected locally.

Hand-off: A maintainer needs to re-trigger CI (close/reopen PR or workflow_dispatch) before merge.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

@copilot merge main and recompile

Done in commit 47afb9f. Merged main (CLI detection, dead code removal), resolved the app.js conflict by integrating the audit state/methods into main's refactored structure, then recompiled all 257 workflows successfully.

@pelikhan pelikhan merged commit be745b1 into main Jun 29, 2026
1 check passed
@pelikhan pelikhan deleted the copilot/update-run-details-view branch June 29, 2026 16:26
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants