From mcs-lab-auditor
Convert a lab's findings.json into a GitHub issue body and file it against the active instance's lab repo (microsoft/mcs-labs by default). Checks for an existing open issue with matching labels and comments on it instead of duplicating. Invoked by mcs-lab-auditor after a lab completes with at least one judge-recorded finding above the confidence threshold. Should NOT be invoked directly by the user — it expects a fully-populated run directory and assumes the orchestrator has already filtered out cannot_verify and below-threshold findings.
How this skill is triggered — by the user, by Claude, or both
Slash command
/mcs-lab-auditor:mcs-lab-issue-filerThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Take the findings for one lab from one audit run and either (a) file a new GitHub issue or (b) comment on an existing open issue for the same lab. Then record the result in `manifest.yml` and `audit-history.yml`.
Take the findings for one lab from one audit run and either (a) file a new GitHub issue or (b) comment on an existing open issue for the same lab. Then record the result in manifest.yml and audit-history.yml.
runs/<run-id>/labs/<slug>/findings.json — list of finding records (see ../mcs-lab-auditor/references/finding-schema.md).runs/<run-id>/manifest.yml — for the run-id, account user-id, plugin-version, etc.<plugin>/config/judge-config.yml — for confidence thresholds, label config, dedupe behavior.C:\Users\dewainr\mcs-labs\_labs\<slug>.md — for the lab title (front-matter).runs/<run-id>/labs/<slug>/issue-body.md — the rendered issue body (kept on disk for audit + retry).github.com/{repo}/issues/<n>.manifest.yml.labs[<slug>]: status: issue_filed, issue_url, issue_action: created|commented.runtime/audit-history.yml: appended entry per audit-log-schema.md.Read findings.json, the lab's front-matter for the title, the run manifest, and the judge config.
Filter findings:
outcome: pass | transient | cannot_verify.confidence < judge-config.yml.confidence.min_to_include_in_issue (typically 0.5).flags.critique_pass_survived == false AND the critique was enabled, drop.If the filtered list is empty, abort cleanly — the orchestrator should have logged this as a clean pass instead of invoking us. Return without creating the issue.
Order findings by:
high → medium → low).Compute summary counts: {high: N, medium: N, low: N} and the highest severity present.
Write runs/<run-id>/labs/<slug>/issue-body.md using this template (variables in {braces}):
## Lab audit: `{slug}` — {lab_title}
**Audit run:** `{run_id}` · **Date:** {iso_timestamp}
**Test account tenant:** {tenant_hint} (workshop-issued)
**Findings:** {N} total — {high}H / {medium}M / {low}L
> Generated by `mcs-lab-auditor` v{plugin_version}. Detailed transcript and screenshots are stored locally at `~/.claude/plugins/mcs-lab-auditor/runtime/runs/{run_id}/labs/{slug}/`.
---
{for each finding}
### Finding {n} — `severity:{level}`{ if 0.5 <= confidence < 0.7: " (low confidence — please verify)" }
<!-- finding:fp:{fingerprint} -->
**Location:** `{scene_heading}` → step {step_ordinal_within_scene} of `_labs/{slug}.md`
**Instruction in lab (verbatim):**
> {instruction_excerpt}
**Expected (per lab):** {expected}
**Observed in UI:** {actual}
**Suggested correction:**
```diff
- {suggested_correction.original_text}
+ {suggested_correction.proposed_text}
Rationale: {suggested_correction.rationale}
Evidence: screenshots/{step_id}.png (in local run artifacts)
{ if console_errors or failed_network: }
Diagnostics:
{ console_errors as "- console: {msg}" lines }
{ failed_network as "- network: {status} {url}" lines }
{end for}
{ if any finding has flags.parser_warning: }
{ for each parser_warning finding: }
{suggested_correction.proposed_text}.{ end if }
Re-audit just this lab against a fresh workshop account:
/audit-lab {slug}
The plugin is at ~/.claude/plugins/mcs-lab-auditor/. See its README for setup details.
This step is mandatory on every run. You may not skip it, and you may not file a new issue when a matching open issue exists. The user's standing rule: never recreate an issue that's already open. If the orchestrator's existing-state probe (runs/<run-id>/existing-state.yml) already resolved an open_issue.number for this slug, use that number directly and jump to step 6.
Otherwise, run two queries and union the results — issues filed before the lab:<slug> label existed will only match the loose query:
Strict (per-slug label present):
gh issue list \
--repo {repo} \
--state open \
--label "lab-audit" \
--label "lab:{slug}" \
--json number,title,url,createdAt \
--limit 10
Loose (slug appears in title, only lab-audit label required):
gh issue list \
--repo {repo} \
--state open \
--label "lab-audit" \
--search "{slug} in:title" \
--json number,title,url,createdAt \
--limit 10
If either query returns at least one result, treat the most recent (by createdAt) as the canonical open issue. Record the number and URL in manifest.yml.labs[<slug>].existing_issue and jump to step 6 (comment).
judge-config.yml.issues.on_duplicate is honored for one purpose only: choosing between "comment" (default — append findings) and "skip" (record issue_action: skipped_duplicate, write nothing). The legacy "create_anyway" value is deprecated and ignored — it is treated as "comment" with a warning logged to the transcript. Filing a new duplicate issue is never an option.
If the existing-state probe has not been run (e.g., issue-filer was invoked outside the orchestrator), perform the two queries above before deciding.
Build the title:
Lab audit: {slug} — {N} finding(s) ({high}H/{medium}M/{low}L)
Build the labels:
labels = ["lab-audit", "lab:{slug}", "severity:{highest_severity}"]
if slug in judge-config.yml.non_deterministic_lab_slugs:
labels.append("non-deterministic-lab")
File the issue:
gh issue create \
--repo {repo} \
--title "{title}" \
--body-file "runs/{run_id}/labs/{slug}/issue-body.md" \
--label "{labels comma-joined}"
Capture stdout — gh prints the new issue URL on the last line. Save as issue_url. Set issue_action: created.
Before posting, fingerprint each finding in findings.json and the existing issue's body + every existing comment, then drop any finding whose fingerprint already appears.
Fingerprint algorithm (SHA-256 hex, first 12 chars):
fingerprint = sha256(
normalize(step_ref) + "|" +
outcome + "|" +
normalize(suggested_correction.original_text or instruction_excerpt)
)[:12]
normalize = lowercase, collapse whitespace, strip leading/trailing punctuation.
To extract existing fingerprints, fetch:
gh issue view <issue-number> --repo {repo} --json body,comments
Parse the body and every comments[].body. Each rendered finding includes a hidden HTML marker <!-- finding:fp:<12-char-hex> --> placed immediately after the finding heading (see step 3 template update). Collect every fingerprint found this way.
A finding is a duplicate if its computed fingerprint matches any extracted fingerprint. Drop duplicates from the comment payload entirely.
If after dedup the comment payload is empty (every finding already covered), do not post a comment. Record:
issue_action: skipped_no_new_findings
issue_url: <existing-issue-url>
and stop. The clean-pass behavior still applies — append an entry to runtime/audit-history.yml noting no new findings.
Re-render issue-body.md using only the surviving (non-duplicate) findings. Prepend a one-line header:
> **Re-audit comment** — run `{run_id}` ({iso_timestamp}). {N} new finding(s) since the last update; duplicates from earlier comments suppressed.
Every finding heading must include the fingerprint marker so the next run can dedup against it:
### Finding {n} — `severity:{level}`
<!-- finding:fp:{fingerprint} -->
gh issue comment <issue-number> \
--repo {repo} \
--body-file "runs/{run_id}/labs/{slug}/issue-body.md"
Capture the comment URL. Save as issue_url. Set issue_action: commented.
If the orchestrator's existing-state probe resolved an open_pr for this slug, append (as a separate comment for clarity):
> Open fix PR for this lab: #{pr_number} (branch `{branch}`). This run's fixes (markdown corrections and/or refreshed screenshots) have been appended to that open PR rather than opening a duplicate — see the PR commits.
After commenting, also re-apply any missing labels with:
gh issue edit <issue-number> --repo {repo} --add-label "lab:{slug}" --add-label "severity:{highest}"
This backfills the per-slug label on issues that pre-date the labeling convention, so future strict-query dedup works without needing the loose query.
Update runs/<run-id>/manifest.yml:
labs:
{slug}:
status: issue_filed
issue_url: <url>
issue_action: created | commented | skipped_duplicate
finished_at: <iso-timestamp>
Append to runtime/audit-history.yml per audit-log-schema.md:
- run_id: <run_id>
lab_slug: {slug}
...
status: issue_filed
issue_url: <url>
issue_action: <action>
findings_summary:
high: N
medium: N
low: N
cannot_verify: N # those filtered out before issue rendering
gh issue list returns an auth error → return status error, reason: gh_unavailable to the orchestrator. The rendered issue-body.md is still on disk for the user to file manually.gh issue create returns rate-limited (HTTP 403) → wait 30s and retry once. If still failing, same fallback as above.Do NOT swallow these errors silently. The user must be told that the issue body is on disk but wasn't filed.
cannot_verify findings in the issue body. They mean "the user's setup couldn't run this step" — not a lab bug. — gh doesn't upload local files. Reference them by path; the maintainer can DM for the artifact if needed._labs/<slug>.md. Suggested corrections are described, not applied.lab-audit label matches the slug (via per-slug label OR title substring), you must comment on it — not create a new one. The on_duplicate: "create_anyway" config value is deprecated and treated as "comment".issue_action: skipped_no_new_findings.<!-- finding:fp:... --> markers from rendered issue bodies or comments. They are how future runs dedup against past output.Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub microsoft/bootcamplabtestplugin --plugin mcs-lab-auditor