| name | vc-self-check |
| description | On-demand self-diagnostician for the vc-fix plugin (Tier B). Reads the passive session-telemetry jsonl + the session transcript + the skill-expectations oracle, and emits a per-skill verdict (OK / DEGRADED / BROKEN) with severity, evidence, a root-cause hypothesis, and a concrete proposed fix (which plugin file/line). Writes a LOCAL DIAG-*.md report only โ it never modifies the installed plugin and never sends anything externally (that is the consent-gated Step-4 delivery). Plugin-wide (covers every vc-fix skill/tool), so it is NOT qa-prefixed. Invoke ONLY on explicit user consent โ the end-of-session consent prompt's "Yes", or when the user runs /vc-self-check directly โ NEVER as an unprompted auto-trigger. Recursion/re-nag is prevented by the collector dropping its own spans + the one-shot consent guard (selfCheckSeen), not by disabling model invocation. |
| argument-hint | [latest | <session-id>] |
/vc-self-check โ vc-fix Self-Diagnostician (Tier B)
The on-demand LLM diagnostician of the self-diagnostics subsystem. The passive
Tier-A collector (hooks/session-telemetry.mjs,
VCST-5475) records what happened every session; this skill reasons about a
session on demand and produces a verdict per shipped skill, judged against the
oracle (knowledge/diagnostics/skill-expectations.md,
VCST-5476).
When it runs. Only on explicit user consent: either the model runs it right after
the user answers Yes to the end-of-session consent prompt (the Stop finalize offers
an AskUserQuestion Yes/No when the skill-attributed anomaly score crosses the
threshold and a skill actually ran; see session-telemetry.mjs), or the user runs
/vc-self-check directly. It is not auto-triggered outside that flow โ do not invoke
it unprompted. No recursion / re-nag: the collector never re-prompts a session that already
ran the diagnostician (selfCheckSeen) and drops vc-self-check spans from its own
analysis, so removing disable-model-invocation (needed so the model can run it on Yes)
does not open a loop.
Scope at this step: LOCAL report only. The output is a DIAG-*.md under the
project's .vc-fix/diagnostics/. Turning a confirmed DIAG into a scrubbed,
consent-gated contribution back to VirtoCommerce is Step 4
(deliver.mjs, VCST-5478) โ mentioned here, never run from
this skill.
Hard invariants
- Read-only w.r.t. the plugin install. NEVER modify installed plugin files.
The "proposed fix" is a written recommendation (file/line), not an applied edit.
- Nothing leaves the machine here. No PR, no issue, no tracker write, no
network send. External delivery is the separate, explicitly-consented Step 4.
- Never diagnose its own invocation. Drop every telemetry span whose skill is
vc-self-check before analysing (the collector also suppresses the consent
prompt for a session that ran the diagnostician โ belt and braces).
- Report discipline. Obey
.claude/rules/reports.md:
DIAG target 15โ40 lines, hard cap ~100 (like a monitoring summary). Reference the
telemetry file by path โ never inline the jsonl.
- English only; never print a secret (the collector already redacts, but do
not surface tokens/PANs from the transcript either).
Flow
Step 0 โ Locate the session telemetry
outputRoot = VC_FIX_HOME || cwd; diagnostics dir = <outputRoot>/.vc-fix/diagnostics/.
latest (default): the newest *.jsonl in that dir is the current session
(ls -t <dir>/*.jsonl | head -1). A specific <session-id> arg reads
<session-id>.jsonl directly.
- If the dir or file is absent โ tell the user telemetry hasn't been collected
(the plugin may be running without the
SessionStart hook wired) and STOP.
- Read the
session_start record for transcriptPath, pluginVersion,
testEnv, projectType.
Step 1 โ Load the oracle
Read knowledge/diagnostics/skill-expectations.md
โ the per-skill expected phases/outputs/anti-patterns and the S0โS3 rubric.
Step 2 โ Build the span list
From the jsonl, assemble each skill span (skill_start โ matching skill_end)
plus the still-open finalize.openSkill, and the session-prefix signals (those
recorded before the first skill_start). Drop any span whose skill matches
vc-self-check (dedup guard). If there are no spans and finalize.anomalyScore
is 0 โ a clean session: report "no issues" (a one-line DIAG is fine) and stop.
Step 3 โ Diagnose each span against the oracle
For each span:
- Take its recorded signal counts (
tool_error, permission_denied,
hook_failure, stop_bail, tool_calls).
- Where a verdict depends on presence/absence of a required phase or output
(the oracle's S1/S2 rows), open the
transcriptPath and confirm โ e.g. did
/qa-fix actually reach a green G2 repro before the PR? did /qa-verify-fix
run Step 2 before the testing transition? was the bug report written and
within its cap?
- Emit, per skill:
- verdict:
OK (S0) / DEGRADED (S2/S3) / BROKEN (S1) โ map via the
oracle rubric. A clean STOP/BAIL is OK.
- severity: S0 / S1 / S2 / S3.
- evidence: the signal counts + a transcript reference (line/turn), no dumps.
- root-cause hypothesis: one or two sentences.
- proposed fix: a concrete plugin file (and line/area if known) โ e.g.
"extend
ALLOWED_PATTERNS in hooks/enforce-real-user.mjs", "trim the bug
report per reports.md ยง4", "the testing transition in commands/qa-verify-fix.md
Step 3 fired before Step 2 confirmed deploy".
Step 4 โ Session-wide cross-cutting check
Evaluate the finalize totals against the oracle's ยง4 cross-cutting table
(tsc-on-every-Edit, browser fallback loop, denied-tool retry storm, oversized
report, silent all-clear on a failed probe, merge attempt, write under the plugin
dir). Add any hit as its own finding.
Step 5 โ Write the LOCAL DIAG report
Write <outputRoot>/.vc-fix/diagnostics/DIAG-<session-id>-<UTC-timestamp>.md
using the template below, within the size cap.
Step 6 โ Report + STOP
Print the DIAG path and a one-line roll-up (e.g. "2 findings: 1 BROKEN, 1
DEGRADED"). If the user wants this sent to VirtoCommerce to improve the plugin,
tell them that is /vc-self-check deliver (Step 4, deliver.mjs) โ a separate,
scrubbed, consent-gated action โ and do not run it here.
DIAG report template
# DIAG โ <session-id>
- Session: <session-id> ยท Plugin: <pluginVersion> ยท Env: <testEnv> ยท Project: <projectType|native>
- Telemetry: `.vc-fix/diagnostics/<session-id>.jsonl` ยท Anomaly score: <n>
## Findings
| Skill | Verdict | Sev | Signal | Root-cause hypothesis | Proposed fix (file) |
|-------|---------|-----|--------|-----------------------|---------------------|
| /qa-fix | BROKEN | S1 | 1ร perm_denied on `gh pr create` | PR auth missing | check `GITHUB_FIX_BUGS_TOKEN` / `gh auth status` |
| /qa-bug | DEGRADED | S2 | report 190 ln (cap 120) | over-long report | trim per reports.md ยง4 |
## Details
<one short paragraph per S1/S2 finding: evidence (transcript ref) + the concrete change.
Skip S0/S3 beyond the table row. Reference telemetry by path; never inline the jsonl.>
_Local report only โ no ticket filed, nothing sent. To contribute this upstream: `/vc-self-check deliver`._
Step 4 (separate, consent-gated) โ deliver upstream
Turning a confirmed DIAG into a scrubbed quality report to VirtoCommerce is
deliver.mjs (VCST-5478) โ invoked as /vc-self-check deliver.
It is not part of the diagnose flow above and is never run implicitly.
node "$pluginRoot/skills/vc-self-check/deliver.mjs" [--diag <path>] [--confirm] [--as pr|fork-pr|issue|local] [--keep] [--purge]
Lifecycle โ log โ analyze โ contribute โ delete. Local diagnostics are EPHEMERAL,
not archived: once a finding is contributed upstream, the source of truth is the
PR/issue, so the processed session's local artifacts are removed.
- Routes by the GitHub token's real rights on
VirtoCommerce/vc-mcp-testing-module
(via ../project-init/probe-lib.mjs): push/maintain/admin โ PR; authenticated
no-push โ fork-PR; issues-only โ GitHub Issue; no token โ local + auth
instructions.
- Containment (ยง2a): every outbound title/body is scrubbed of client source,
paths, URLs, identifiers, tickets, and secrets โ only plugin-file references +
generic repro survive; a client-specific finding is downgraded to a generic line.
- Draft-and-confirm: the default run is DRY (writes a
DELIVERY-*.md draft and
shows it). It sends ONLY with --confirm, and even then auto-files just the
Issue route; a PR/fork-PR is handed off as ready commands. Issue dedup via a
stable fingerprint marker. It never touches the client-installed plugin.
- Delete-after-deliver (the "delete all" step): the cleanup is scoped to the
processed session only (its
<sid>.jsonl + .state.json + DIAG-<sid>-*.md
- this finding's
DELIVERY-*.md) โ other sessions are never touched.
- Issue route +
--confirm (filed, or a dedup that is already upstream) โ
the session's local artifacts are deleted automatically. --keep retains them.
- PR / fork-PR (handed off โ the human opens the PR) and local (no token,
nothing sent) โ nothing is deleted; the run prints the ready cleanup command
to run after the PR is opened / after authenticating.
- Nothing worthwhile (no BROKEN/DEGRADED finding) โ files nothing and offers the
cleanup command.
--purge is the standalone terminal step: delete this session's local
artifacts and send nothing (used after a hand-off PR is opened, or to discard a
non-actionable session).
Notes
- Verdict/severity semantics and the (signal ร expectation) table live in the
oracle โ cite them, don't restate.
- If two spans share a root cause (e.g. the same
tsc hook failing across skills),
merge them into one finding and note the affected skills.
- A
LOW-confidence diagnosis is fine โ say so; better an honest "unclear, here's
the evidence" than a confident wrong fix.