[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DYX92A5FMGKWSC0DASSCFE":3,"skill-same:01M6DYX92A5FMGKWSC0DASSCFE":94},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":48,"commitSha":49,"skillDirectory":50,"forksCount":51,"repositoryHtmlUrl":52,"repositoryHomepageUrl":53,"ownerHtmlUrl":54,"ownerBlogUrl":55,"ownerDescription":56,"updatedAt":57,"install":58,"resources":71},"01M6DYX92A5FMGKWSC0DASSCFE","grade-tests",null,"Grade curated individual tests for readiness, A-F quality and improvements. ALWAYS USE FOR: grade tests, review only a named test, per-test readiness or quality bands for supplied methods, bodies, file spans or bounded PR diffs, including existing tests. Return Pass\u002FFailed\u002FUncertain\u002FNot applicable; unresolved\u002Fempty scopes omit grades. Compose read-only per-test evidence. Polyglot. DO NOT USE FOR: suite audits (test-engineer\u002Ftest-anti-patterns), concrete fix\u002Ffeature detection proof (test-value-evidence), writing\u002Ffixing tests, or coverage.","managedcode\u002Fdotnet-skills","managedcode","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F78253589?v=4","01M6DYDJR3EG8KB5G4PC65XCTT","Managed Code","01M6DYDJX0ZT432N04NYJW89DN",512,"MIT","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FTesting\u002FOfficial-DotNet-Test\u002Fskills\u002Fgrade-tests\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"grade tests","tests","only","suite","value","bounded","feature","patterns","do","methods","engineer","compose","evidence","writing","anti-patterns","use","fix","coverage","read","polyglot","pr","diffs","review","2026-11-10 10:12:30",false,"---\nname: grade-tests\ndescription: >\n  Grade curated individual tests for readiness, A-F quality and improvements.\n  ALWAYS USE FOR: grade tests, review only a named test, per-test readiness or\n  quality bands for supplied methods, bodies, file spans or bounded PR diffs,\n  including existing tests. Return Pass\u002FFailed\u002FUncertain\u002FNot applicable;\n  unresolved\u002Fempty scopes omit grades. Compose read-only per-test evidence.\n  Polyglot. DO NOT USE FOR: suite audits (test-engineer\u002Ftest-anti-patterns),\n  concrete fix\u002Ffeature detection proof (test-value-evidence), writing\u002Ffixing\n  tests, or coverage.\nlicense: MIT\n---\n\n# Grade Tests\n\nAssess a curated list of test methods and produce a compact,\nPR-comment-friendly report. The primary result is one of **Pass**, **Failed**,\n**Uncertain**, or **Not applicable**; an A-F quality grade remains secondary\ndiagnostic information. The skill **does not discover tests on its own** — the\ncaller (typically a PR automation workflow or a human reviewer holding a\nspecific list) provides the tests or a bounded diff to assess.\n\nAfter Step 0 admits a bounded scope, enforce these grading invariants:\n\n- With production context, **load `test-gap-analysis` by name once before\n  scoring**, in `per-test-read-only` caller context. Read its owned composition\n  reference; do not compute mutation evidence from this grading rubric or run\n  its standalone workflow. Report N\u002FA \u002F unverified only when the dependency,\n  reference, or required context is actually unavailable.\n- Any reported mutation inference must use **Likely killed (inferred)** or\n  **Candidate survivor (unverified)**, even when explained in prose.\n- Apply only the rubric below, not extra heuristics such as a duplicate-test\n  penalty. Do not use sibling tests to alter the individual assessment.\n- A **B** quality grade does not require a Failed result; a complete focused\n  test may have no actionable change.\n\n> **Language-specific guidance**: Read the caller-provided matching extension\n> file, or the runtime-listed `test-analysis-extensions` catalog and its matching\n> language file. The reference-only helper is not an invocable skill. If its\n> files are absent, use the embedded rubric and pinned framework APIs; mark an\n> essential unresolved framework construct Uncertain instead of guessing or\n> searching installation directories.\n\n## Why a Decision Result Plus Quality Detail\n\nPR reviewers need a simple answer to *does this test need follow-up?* The\nfour-state result provides that decision; the existing A-F rubric explains its\nquality and severity.\n\n## When to Use\n\n- A PR automation workflow needs to post a decision on the tests introduced or\n  modified in a pull request.\n- A reviewer has a specific list of tests (a file, a class, a method list,\n  or a diff hunk) and wants per-test follow-up decisions rather than a suite\n  report.\n- A maintainer wants to triage which of N tests in a contribution deserve\n  follow-up improvements, with quality grades for resolved tests.\n\n## When Not to Use\n\n- The caller wants a full suite audit or comparative metrics — use\n  `test-anti-patterns` (pragmatic) or `test-smell-detection` (formal) and\n  let the `test-engineer` agent orchestrate its internal quality specialist.\n- The caller wants to *write* new tests — use `test-engineer`\n  (any language) or `writing-mstest-tests` (MSTest specifically).\n- The caller wants to measure code coverage or CRAP scores — use\n  `coverage-analysis` or `crap-score` (.NET only).\n- The caller wants to fix issues directly in test code — invoke the\n  appropriate editing skill.\n- No specific list of tests is provided. Do **not** try to grade every test\n  in the workspace; ask the caller for an explicit list or scope.\n\n## Inputs\n\n| Input | Required | Description |\n|-------|----------|-------------|\n| Test methods | Yes | A scope to grade. Provide one of: (a) an explicit list of test method names (fully-qualified, e.g. `Namespace.ClassName.TestMethodName`); (b) one or more file paths plus an explicit instruction to grade every test declared in those files; or (c) a diff hunk \u002F PR identifier whose changed tests should be graded. File paths are recommended but optional when method names are unambiguous in the workspace. Ambiguous requests like *\"grade my tests\"* with no scope are rejected up-front (see Step 0); this skill is for curated input and does not auto-grade an entire workspace. |\n| Test bodies \u002F spans | Recommended | The exact source lines for each test method. If omitted, read them from the listed files. |\n| Production code | No | The code under test, for judging whether assertions cover the claimed behavior. When unavailable, mark the mutation assessment N\u002FA \u002F unverified rather than guessing or deducting. |\n| Language reference | No | A host-supplied path to the matching bundled `test-analysis-extensions` file. Read it directly instead of invoking its reference-only loader; do not substitute unverified framework guidance. |\n| Diff context | No | When grading PR changes, the unified diff for each test method helps focus on what actually changed. |\n\n### Step 0: Validate the input\n\nBefore doing anything else, check that the caller provided one of:\n\n1. An explicit list of test method names, **or**\n2. One or more file paths plus an explicit instruction to grade every test\n   declared in those files (e.g., \"grade every test in `OrderTests.cs`\"), **or**\n3. A diff hunk or PR identifier whose changed tests should be graded.\n\nIf the request is ambiguous (e.g., *\"Grade my tests\"*, *\"Are these tests\nany good?\"* with no scope, *\"Review the test suite\"*), **do not load\nextensions, do not read files, and do not grade anything**. Reply with a\nshort message asking the caller to provide an explicit list \u002F file(s) \u002F\ndiff, and optionally point them at the `test-engineer` agent or\n`test-anti-patterns` skill for full-suite analysis. Stop there.\n\nIf a valid bounded scope resolves to zero eligible tests, return\n**Not applicable** with a short explanation and no invented rows.\n\n## Workflow\n\n### Step 1: Detect language and load extension\n\nIdentify the target codebase's language and test framework from the file\nextensions and the test method markers in the provided list. Read the matching\ncaller-provided extension file directly; otherwise read the matching\n`extensions\u002F` file relative to the runtime-listed `test-analysis-extensions`\ncatalog (`dotnet.md`, `python.md`, `typescript.md`, `go.md`, etc.).\nUse the catalog for other languages, not a skill invocation.\nIf the input contains tests from\nmultiple languages, load each relevant extension and grade each test using\nits language's conventions.\n\n### Step 2: Resolve the test bodies\n\nFor each entry in the input list:\n\n1. If the test body is provided inline, use it directly.\n2. Otherwise read the file at the given path and locate the method by its\n   fully-qualified name. Capture the full method body, including attributes\n   \u002F decorators \u002F fixtures and any helper code that the test calls.\n3. If a requested method cannot be found, record it as\n   `Uncertain — method not found` with no quality grade and continue. Never\n   invent a body to grade. A missing requested method requires human review;\n   it is not the same as a valid scope containing no tests.\n\n**Composition checkpoint:** for resolved tests with available production\ncontext, load `test-gap-analysis` now, once for the batch, with\n`per-test-read-only` assessment context. Complete its owned reference assessment\nbefore Step 3. Do not skip this load just because a body-level weakness already\nseems obvious; a locally invented mutation explanation is not composition.\n\n### Step 3: Assess the claimed behavior and score each resolved test\n\nKeep grading read-only: no build\u002Ftest runs, mutation execution, file edits,\ntool installation, broad suite discovery, or agent delegation. Resolve only\nthe supplied tests, their relevant fixtures\u002Fhelpers, and the production call\nchain needed for their claims.\n\nUse the inline `test-gap-analysis` assessment from Step 2's checkpoint;\ndo not load it a second time. Supply each test's\nidentifier\u002Fbody, relevant setup\u002Fhelpers, claimed behavior, assertion semantics,\nand available source. Its composition dispatch loads the owned read-only\nreference rather than its standalone baseline\u002Fverification workflow. Consume\nits per-test evidence; do not duplicate its mutation catalog here or invoke an\naudit\u002Fgeneration agent.\nConvey mode and inputs as assessment context using the host's supported caller\ninstructions. If the loader accepts only a skill name, load `test-gap-analysis`\nby name only; do not invent tool arguments or a mode-specific skill name.\n\nIf the skill\u002Freference or production context is unavailable, record\n`Pseudo-mutation: N\u002FA \u002F unverified — \u003Creason>` and continue normal body-level\ngrading. This is not a grade deduction or, by itself, an Uncertain result.\nDo not search installation directories or substitute a mutation runner.\n\nAssess only what each test claims: do not borrow another test's assertions,\nor demand unrelated branches, outputs, or scenarios. An observable survivor\ncan support an existing Assertion strength category when it proves that the\ntest does not verify its claimed outcome; do not introduce mutation points,\nweights, ceilings, or an automatic survivor penalty. Apply the existing rubric\nnormally, including weaknesses it classifies in both Assertion and Anti-pattern\ndimensions; do not add another deduction for the same mutation evidence.\n\nStart every test at grade **A (score band 90–100)**, then apply deductions\nstrictly for **observable issues** in the captured body. Do **not** deduct\nfor hypothetical concerns (e.g., \"could have more negative assertions\")\nunless the production code clearly demands them and the production code is\navailable.\n\nWhen production code is unavailable, grade observable issues in the test body\nnormally, but do not infer missing behaviors or deduct for them. State\n`Production-dependent behavior coverage: Unverified` once in the summary so the\nreader can distinguish test-body findings from claims that require source code.\n\n#### Three sub-dimensions\n\nCompute three sub-grades (each A–F) that together drive the overall grade.\n\n##### A. Assertion strength\n\nRead the loaded language extension's assertion API list and classify every\nassertion in the test body. Score from highest to lowest:\n\n| Sub-grade | Pattern |\n|-----------|---------|\n| **A** | Pins a richer contract through structural equality or nonredundant related observables (such as returned values plus required state\u002Finteraction checks), or qualifies for the exception\u002Ferror calibration below. Grade predicate depth, not assertion count. Mock-call verifications and bare language assertions count normally. |\n| **B** | One clear meaningful assertion that verifies the behavior under test. |\n| **C** | Only trivial assertions (single `IsNotNull` \u002F `toBeDefined` \u002F `assert x is not None`), or assertions that leave a meaningful part of the test's claimed result unchecked. A focused single-field claim does not require unrelated fields. |\n| **D** | One self-referential \u002F tautological assertion (`Assert.AreEqual(x, x)`, `assert dto.name == dto.name`, round-trip identity without a non-trivial input), or broad exception assertions (`Assert.ThrowsException\u003CException>`). |\n| **F** | No assertions at all; **all** assertions are always-true literals (`Assert.IsTrue(true)`, `assert True`, `expect(true).toBe(true)`) — these verify nothing and are equivalent to having no assertions; or all assertions are silently un-awaited (e.g., `expect(promise).resolves.toBe(x)` without `await`\u002F`return`, async TUnit\u002FxUnit `Assert.ThrowsAsync` without `await`, pytest-asyncio with un-awaited coroutine). |\n\nException and error-path tests (`Assert.ThrowsException\u003CT>`, constrained\n`pytest.raises`, `expect(fn).toThrow`, `assertThrows`, `#[should_panic]`,\n`Should -Throw`, `EXPECT_THROW`, or Go code that verifies an expected non-nil\nerror) are complete on their own. Give Assertion strength **A** when the test\nchecks the exact promised error condition for its stated scope. Do not deduct\nfor having only that assertion, and do not require an error-message assertion\nunless the message is part of the documented contract. A Go happy-path test\nthat only checks `err == nil` while discarding a meaningful returned value is\nstill **C** because it does not verify the successful result.\n\n##### B. Structure & focus\n\n| Sub-grade | Pattern |\n|-----------|---------|\n| **A** | Clear Arrange-Act-Assert (or Given-When-Then) separation. Single behavior under test. Body under ~30 lines. Setup uses framework conventions. |\n| **B** | One mild structural issue (slightly long body, missing blank lines between phases) but intent is clear. |\n| **C** | Multiple behaviors mixed in one test, or AAA phases interleaved enough to slow comprehension. |\n| **D** | Conditional logic in the test (`if`\u002F`switch` driving assertions) — except for idiomatic Go\u002FRust table-driven sub-test loops; or test relies on previous test state (ordering dependency). |\n| **F** | Test exceeds ~60 lines and verifies multiple unrelated behaviors; or shares mutable state with other tests through statics\u002Fglobals without reset. |\n\n##### C. Anti-pattern hygiene\n\nScan against the catalog below. The Anti-pattern sub-grade is computed\nin two passes and combined deterministically:\n\n1. **Hard ceiling pass.** Every **Critical** or **High** finding sets a\n   maximum sub-grade (F, D, or C as labeled). Take the **worst** ceiling\n   across all matched Critical\u002FHigh findings — these do not accumulate\n   (a single F finding caps the sub-grade at F regardless of how many\n   other Critical\u002FHigh findings are present).\n2. **Medium-deduction pass.** Start from **A**, then for each **Medium**\n   finding deduct one sub-grade level (A→B, B→C, C→D, D→F). These do\n   accumulate across findings.\n\nThe final Anti-pattern sub-grade is the **worse** of the two passes\n(i.e., `min(hard_ceiling, A − medium_count)`). **Low** findings never\naffect the grade — mention them in the note only.\n\nExamples (Critical\u002FHigh and Medium counts → Anti-pattern sub-grade):\n\n- Zero Critical\u002FHigh, 1 Medium → **B** (A − 1)\n- Zero Critical\u002FHigh, 3 Medium → **D** (A − 3)\n- One C-ceiling (e.g., over-mocking), 0 Medium → **C**\n- One C-ceiling, 2 Medium → **C** (`min(C, A − 2 = C) = C`; a third Medium tips to **D**)\n- One F-finding (e.g., swallowed exception) plus any number of Medium → **F**\n\n**Critical (drop straight to F or D)**\n\n- No assertions at all → F (also drives Assertion sub-grade to F)\n- Swallowed exceptions: `try { … } catch { }` (.NET), bare `except: pass`\n  (Python), `try { … } catch (e) {}` (JS\u002FTS\u002FJava), `defer recover()`\n  without re-panic (Go), `rescue StandardError` with no assertion (Ruby),\n  empty `catch` (Kotlin\u002FSwift) → F\n- Assert-in-catch pattern (`Assert.Fail(ex.Message)` instead of\n  `Assert.ThrowsException`) → D\n- Always-true literal assertions (`Assert.IsTrue(true)`, `assert True`,\n  `expect(true).toBe(true)`) → **F** (verifies nothing; also drives\n  Assertion sub-grade to F)\n- Self-referential \u002F tautological assertions on bound values\n  (`Assert.AreEqual(x, x)`, `assert dto.name == dto.name`) → D\n- Commented-out assertions → D\n\n**High (drop one or two sub-grades)**\n\n- Wall-clock sleep used for synchronization: `Thread.Sleep`, `Task.Delay`,\n  `time.sleep`, `setTimeout`-based wait, `Thread.sleep`, `time.Sleep`,\n  `sleep`, `std::thread::sleep`, `Start-Sleep`,\n  `std::this_thread::sleep_for` (in a unit test) → D\n- Unseeded randomness, wall-clock reads without abstraction\n  (`DateTime.Now`, `datetime.now()`, `Date.now()`,\n  `System.currentTimeMillis()`, `time.Now()`, `Time.now`,\n  `Instant::now()`, `Get-Date`, `system_clock::now`) → D\n- Hard-coded environment-dependent paths (`C:\\…`, `\u002Ftmp\u002F…`, network hosts) → D\n- Ordering dependency on mutable static \u002F package globals → D\n- Broad exception assertion (`Assert.ThrowsException\u003CException>`,\n  `pytest.raises(Exception)`, `expect(fn).toThrow(Error)` without matcher,\n  `#[should_panic]` without `expected = \"…\"`, `Should -Throw` without\n  `-ExpectedMessage`, `EXPECT_ANY_THROW`) → C\n- Over-mocking: more mock setup lines than test logic, or verifying exact\n  call sequences instead of outcomes → C\n- Implementation coupling: reflection on private members, casting to\n  internal types to access state → C\n\n**Medium (drop one sub-grade)**\n\n- Poor name: `Test1`, `TestMethod`, `test`, single-word name that says\n  nothing about scenario or expected outcome (judge against the language\n  extension's convention) → drop one sub-grade\n- Magic values: unexplained `42`, `\"foo\"`, `0x1234` in arrange\u002Fassert\n  without naming or comment → drop one sub-grade\n- Giant test (>30 lines covering a single behavior) → drop one sub-grade\n- Assertion messages that just repeat the assertion text → drop one sub-grade\n- Missing AAA \u002F GWT separation when the test is non-trivial → drop one sub-grade\n\n**Low (note only, no deduction)**\n\n- Unused setup\u002Fteardown hooks; print debugging left in (`Console.WriteLine`,\n  `print`, `console.log`, `System.out.println`, `fmt.Println`, `puts`,\n  `dbg!`, `Write-Host`, `std::cout`); inconsistent naming versus siblings;\n  leftover TODO comments. Mention in the note column but do not deduct.\n\n#### Combining sub-grades\n\nConvert sub-grades to numeric points: A=4, B=3, C=2, D=1, F=0.\n- **Overall score band** = weighted average:\n  `0.45 × Assertion + 0.30 × Anti-pattern + 0.25 × Structure`\n- Map to letter:\n  - ≥ 3.5 → **A** (band 90–100)\n  - ≥ 2.8 → **B** (band 80–89)\n  - ≥ 2.0 → **C** (band 70–79)\n  - ≥ 1.2 → **D** (band 60–69)\n  - \u003C 1.2 → **F** (band 0–59)\n- The overall grade is **capped at the worst sub-grade** — if any sub-grade\n  is **F**, the overall grade is **F**; if the worst sub-grade is **D**,\n  the overall grade is at most **D**; and so on. A test that fails on any\n  one dimension cannot earn a higher overall grade than that dimension.\n\nApply the cap after the weighted mapping, not instead of it. For example,\nAssertion B, Anti-pattern A, Structure A gives `3.55`: the provisional weighted\ngrade is A, but the final grade is **B (80-89)**. A focused scalar equality can\ntherefore be **B \u002F Pass** with no actionable finding; do not invent a weakness\nor missing sibling behavior to justify that grade.\n\nReport the **letter grade** and the **score band** (not a single 0–100\nnumber). False precision invites bikeshedding; bands keep the conversation\nfocused on the rubric.\n\n### Step 4: Assign the decision result\n\nThe grade summarizes strength; the result says whether follow-up exists.\nAn actionable improvement is an evidence-backed change to the test, setup, or\nfixtures. Assign exactly one:\n\n- **Pass** — no actionable improvement; positive\u002Fcontext-only notes are allowed.\n- **Failed** — at least one actionable improvement, regardless of grade.\n- **Uncertain** — missing evidence prevents a decision and needs human review.\n- **Not applicable** — a valid scope contains no eligible tests; normally an\n  overall result with no rows.\n\nDo not derive status from grade: a complete focused test can be **B \u002F Pass**,\nwhile debug output can make an otherwise excellent test **A \u002F Failed**. Use\nUncertain for an unresolved body, unsupported construct, or essential missing\ncontract—not merely absent production code. A definite finding wins over\nuncertainty.\n\n### Step 5: Build the note\n\nUse one sentence (target ≤ 120 characters) for the most important reason:\n`No issues found.`, `Only checks IsNotNull; receipt contents are unverified.`, or\n`Method body could not be resolved; human review is required.` Do not invent a\nweakness to justify a grade or Failed result.\n\nKeep the action in a separate **How to improve** field. For each Failed test,\nname the smallest useful input, assertion, or fixture change and its expected\noutcome, grounded in the body, source, or an explicit contract. For example,\n`Replace self-comparison with Assert.AreEqual(60m, account.Balance).`, not\n`Improve assertions`; `Remove Console.WriteLine after Deposit(25m).`, not\n`Clean up`. Prioritize the highest-impact distinct finding, and include other\nactionable findings only when they require a different change.\n\nFor a behavioral gap, use the distinguishing witness and original\u002Fmutant\nobservations from the shared assessment; check the expected result against\nthe unmodified source. If essential context is missing, name the evidence\nneeded instead of inventing an expected value. Pass gets `None`; Uncertain\ngets a concrete evidence-resolution step, not a speculative test rewrite.\nA rubric-only deduction is not proof of a behavioral gap or an actionable\nimprovement: a focused **B \u002F Pass** may need no change. **A \u002F Failed** still\nneeds its concrete action, such as removing debug output.\n\n### Step 6: Report\n\nProduce two sections.\n\n#### 1. Summary\n\nBegin with `**Result: \u003CPass|Failed|Uncertain|Not applicable>**`, then give result\ncounts and the highest-priority action. Aggregate using\n**Failed → Uncertain → Pass → Not applicable**. For Not applicable, explain the\nempty scope and omit the table.\n\n#### 2. Per-test table\n\n```markdown\n| Test | Result | Quality | Notes | How to improve |\n|------|--------|---------|-------|----------------|\n| `Namespace.ClassName.Test_Method_Condition_Expected` | Pass | B (80–89) | One complete value assertion. | None |\n| `Namespace.ClassName.Withdraw_SufficientFunds` | Failed | D (60–69) | Balance is compared with itself. | Replace self-comparison with `Assert.AreEqual(60m, account.Balance)` after withdrawing 40m from 100m. |\n| `Namespace.ClassName.Test_Missing` | Uncertain | — | Method body could not be resolved; human review is required. | Supply the method body and its referenced fixture. |\n```\n\nKeep these two report sections and the original Test\u002FResult\u002FQuality\u002FNotes\nfields. When mutation evidence explains a finding or the caller requests\ndetail, append a compact per-test **Pseudo-mutation evidence** block inside\nthe per-test section: change, witness, original\u002Fmutant observations, relevant\nassertion, and classification. Static results are **Likely killed (inferred)**\nor **Candidate survivor (unverified)**, never executed Killed\u002FSurvived or\nempirical killed\u002Ftotal counts. State missing-context N\u002FA \u002F unverified once\nper shared limitation. Do not repeat the improvement table in prose.\n\n**Caps and ordering**:\n- If the table would exceed **50 rows**, show Failed tests first, then\n  Uncertain tests, then a sample of Pass tests. Wrap overflow in a collapsed\n  `\u003Cdetails>` block.\n- Within the same result, order by quality from worst to best, then by file\n  path and method name for determinism.\n- If the diff context is provided, prefix each test name with a `(new)` or\n  `(modified)` marker.\n\nIf multiple languages are present, produce one table per language and\nprefix each section with the language name and framework.\n\n## Validation\n\n- [ ] Every test in the input list appears in the table (or is recorded as\n      `Uncertain — method not found`).\n- [ ] Every resolved test has Pass or Failed plus A-F quality detail.\n- [ ] Uncertain is an evidence gap; Not applicable is a valid empty scope.\n- [ ] Every grade is justified by at least one observable signal in the\n      captured body — no speculative deductions.\n- [ ] Every Failed row has a concrete, evidence-backed How to improve action;\n      Pass rows have no invented weakness, even when the quality grade is B.\n- [ ] Mutation assessment stayed read-only and per-test; unavailable context\n      was not penalized, equivalents were excluded, and static labels\u002Fcounts\n      were not presented as executed evidence.\n- [ ] Verified observable findings inform existing categories without a\n      duplicate deduction or any change to scoring weights and ceilings.\n- [ ] Trivial-assertion tests are flagged only when the **only** assertion\n      is trivial (a null check before a meaningful assertion is not trivial).\n- [ ] Exception-only tests are not penalized for low assertion count.\n- [ ] Mock-call verifications and bare assertion forms count as real\n      assertions of the appropriate category.\n- [ ] Boolean assertions on meaningful properties (`Assert.IsTrue(result.IsValid)`)\n      are not classified as always-true; only literal `true`\u002F`false` constants are.\n- [ ] Self-referential assertions are flagged separately from normal\n      equality assertions.\n- [ ] Idiomatic patterns are not flagged: Go\u002FRust table-driven sub-tests,\n      pytest bare `assert`, Go `if got != want { t.Errorf(...) }`,\n      JS\u002FTS `expect(mock).toHaveBeenCalledWith(...)`.\n- [ ] Async test pitfalls (un-awaited `resolves`\u002F`rejects`\u002F`ThrowsAsync`,\n      pytest-asyncio without `await`) drop the Assertion sub-grade to F.\n- [ ] The summary leads with the highest-leverage observation, not a recap\n      of the table.\n\n## Common Pitfalls\n\n| Pitfall | Solution |\n|---------|----------|\n| Grading every test in the workspace when no list is provided | Ask the caller for the explicit list; this skill is for curated input. |\n| Inflating deductions to justify the grade | Start at A; deduct only for observable issues. |\n| Penalizing exception tests for low assertion count | Exception assertions are complete on their own. |\n| Downgrading a focused Go error-path test because it checks only `err != nil` | Expected-error existence is the observable contract for that scope; keep it at A unless the production contract requires a specific error identity or message. |\n| Treating `IsNotNull` before a value assertion as trivial | Only flag when the null check is the **only** assertion. |\n| Treating any Boolean assertion as effectively assertion-free | Only always-true literals (`Assert.IsTrue(true)`, `assert True`) are; meaningful `Assert.IsTrue(result.IsValid)` is a real assertion. |\n| Flagging Go\u002FRust table-driven loops as conditional logic | They are idiomatic; do not deduct. |\n| Treating pytest bare `assert` or Go `if got != want { t.Error… }` as missing-framework | Both are canonical; count in the correct assertion category. |\n| Penalizing tests when production code is unavailable | Mark concerns about uncovered behaviors as `Unverified` and do not deduct. |\n| Using a fake-precise score (e.g., 87\u002F100) | Use the score band only — 90–100, 80–89, 70–79, 60–69, 0–59. |\n| Spilling a 500-row table into a PR comment | Apply the row cap from Step 6; collapse extras into `\u003Cdetails>`. |\n| Re-reporting an existing finding three times under different categories | Pick the most fitting category and report once. |\n| Giving a weak test credit for a sibling's assertions | Use only the current test and helpers\u002Ffixtures it executes. |\n| Turning pseudo-mutation composition into a suite audit | Pass explicit per-test-read-only mode; no runs, edits, broad discovery, or agent recursion. |\n| Inventing weaknesses for A-grade tests to make the note \"balanced\" | If a test is clean, the note may simply read `No issues found.` |\n| Mapping status from grade or comments | Fail only for actionable improvements; a B can Pass and an A can Fail. |\n| Confusing Uncertain and Not applicable | Evidence gaps are Uncertain; a valid empty scope is Not applicable. |\n","# Grade Tests\n\nAssess a curated list of test methods and produce a compact,\nPR-comment-friendly report. The primary result is one of **Pass**, **Failed**,\n**Uncertain**, or **Not applicable**; an A-F quality grade remains secondary\ndiagnostic information. The skill **does not discover tests on its own** — the\ncaller (typically a PR automation workflow or a human reviewer holding a\nspecific list) provides the tests or a bounded diff to assess.\n\nAfter Step 0 admits a bounded scope, enforce these grading invariants:\n\n- With production context, **load `test-gap-analysis` by name once before\n  scoring**, in `per-test-read-only` caller context. Read its owned composition\n  reference; do not compute mutation evidence from this grading rubric or run\n  its standalone workflow. Report N\u002FA \u002F unverified only when the dependency,\n  reference, or required context is actually unavailable.\n- Any reported mutation inference must use **Likely killed (inferred)** or\n  **Candidate survivor (unverified)**, even when explained in prose.\n- Apply only the rubric below, not extra heuristics such as a duplicate-test\n  penalty. Do not use sibling tests to alter the individual assessment.\n- A **B** quality grade does not require a Failed result; a complete focused\n  test may have no actionable change.\n\n> **Language-specific guidance**: Read the caller-provided matching extension\n> file, or the runtime-listed `test-analysis-extensions` catalog and its matching\n> language file. The reference-only helper is not an invocable skill. If its\n> files are absent, use the embedded rubric and pinned framework APIs; mark an\n> essential unresolved framework construct Uncertain instead of guessing or\n> searching installation directories.\n\n## Why a Decision Result Plus Quality Detail\n\nPR reviewers need a simple answer to *does this test need follow-up?* The\nfour-state result provides that decision; the existing A-F rubric explains its\nquality and severity.\n\n## When to Use\n\n- A PR automation workflow needs to post a decision on the tests introduced or\n  modified in a pull request.\n- A reviewer has a specific list of tests (a file, a class, a method list,\n  or a diff hunk) and wants per-test follow-up decisions rather than a suite\n  report.\n- A maintainer wants to triage which of N tests in a contribution deserve\n  follow-up improvements, with quality grades for resolved tests.\n\n## When Not to Use\n\n- The caller wants a full suite audit or comparative metrics — use\n  `test-anti-patterns` (pragmatic) or `test-smell-detection` (formal) and\n  let the `test-engineer` agent orchestrate its internal quality specialist.\n- The caller wants to *write* new tests — use `test-engineer`\n  (any language) or `writing-mstest-tests` (MSTest specifically).\n- The caller wants to measure code coverage or CRAP scores — use\n  `coverage-analysis` or `crap-score` (.NET only).\n- The caller wants to fix issues directly in test code — invoke the\n  appropriate editing skill.\n- No specific list of tests is provided. Do **not** try to grade every test\n  in the workspace; ask the caller for an explicit list or scope.\n\n## Inputs\n\n| Input | Required | Description |\n|-------|----------|-------------|\n| Test methods | Yes | A scope to grade. Provide one of: (a) an explicit list of test method names (fully-qualified, e.g. `Namespace.ClassName.TestMethodName`); (b) one or more file paths plus an explicit instruction to grade every test declared in those files; or (c) a diff hunk \u002F PR identifier whose changed tests should be graded. File paths are recommended but optional when method names are unambiguous in the workspace. Ambiguous requests like *\"grade my tests\"* with no scope are rejected up-front (see Step 0); this skill is for curated input and does not auto-grade an entire workspace. |\n| Test bodies \u002F spans | Recommended | The exact source lines for each test method. If omitted, read them from the listed files. |\n| Production code | No | The code under test, for judging whether assertions cover the claimed behavior. When unavailable, mark the mutation assessment N\u002FA \u002F unverified rather than guessing or deducting. |\n| Language reference | No | A host-supplied path to the matching bundled `test-analysis-extensions` file. Read it directly instead of invoking its reference-only loader; do not substitute unverified framework guidance. |\n| Diff context | No | When grading PR changes, the unified diff for each test method helps focus on what actually changed. |\n\n### Step 0: Validate the input\n\nBefore doing anything else, check that the caller provided one of:\n\n1. An explicit list of test method names, **or**\n2. One or more file paths plus an explicit instruction to grade every test\n   declared in those files (e.g., \"grade every test in `OrderTests.cs`\"), **or**\n3. A diff hunk or PR identifier whose changed tests should be graded.\n\nIf the request is ambiguous (e.g., *\"Grade my tests\"*, *\"Are these tests\nany good?\"* with no scope, *\"Review the test suite\"*), **do not load\nextensions, do not read files, and do not grade anything**. Reply with a\nshort message asking the caller to provide an explicit list \u002F file(s) \u002F\ndiff, and optionally point them at the `test-engineer` agent or\n`test-anti-patterns` skill for full-suite analysis. Stop there.\n\nIf a valid bounded scope resolves to zero eligible tests, return\n**Not applicable** with a short explanation and no invented rows.\n\n## Workflow\n\n### Step 1: Detect language and load extension\n\nIdentify the target codebase's language and test framework from the file\nextensions and the test method markers in the provided list. Read the matching\ncaller-provided extension file directly; otherwise read the matching\n`extensions\u002F` file relative to the runtime-listed `test-analysis-extensions`\ncatalog (`dotnet.md`, `python.md`, `typescript.md`, `go.md`, etc.).\nUse the catalog for other languages, not a skill invocation.\nIf the input contains tests from\nmultiple languages, load each relevant extension and grade each test using\nits language's conventions.\n\n### Step 2: Resolve the test bodies\n\nFor each entry in the input list:\n\n1. If the test body is provided inline, use it directly.\n2. Otherwise read the file at the given path and locate the method by its\n   fully-qualified name. Capture the full method body, including attributes\n   \u002F decorators \u002F fixtures and any helper code that the test calls.\n3. If a requested method cannot be found, record it as\n   `Uncertain — method not found` with no quality grade and continue. Never\n   invent a body to grade. A missing requested method requires human review;\n   it is not the same as a valid scope containing no tests.\n\n**Composition checkpoint:** for resolved tests with available production\ncontext, load `test-gap-analysis` now, once for the batch, with\n`per-test-read-only` assessment context. Complete its owned reference assessment\nbefore Step 3. Do not skip this load just because a body-level weakness already\nseems obvious; a locally invented mutation explanation is not composition.\n\n### Step 3: Assess the claimed behavior and score each resolved test\n\nKeep grading read-only: no build\u002Ftest runs, mutation execution, file edits,\ntool installation, broad suite discovery, or agent delegation. Resolve only\nthe supplied tests, their relevant fixtures\u002Fhelpers, and the production call\nchain needed for their claims.\n\nUse the inline `test-gap-analysis` assessment from Step 2's checkpoint;\ndo not load it a second time. Supply each test's\nidentifier\u002Fbody, relevant setup\u002Fhelpers, claimed behavior, assertion semantics,\nand available source. Its composition dispatch loads the owned read-only\nreference rather than its standalone baseline\u002Fverification workflow. Consume\nits per-test evidence; do not duplicate its mutation catalog here or invoke an\naudit\u002Fgeneration agent.\nConvey mode and inputs as assessment context using the host's supported caller\ninstructions. If the loader accepts only a skill name, load `test-gap-analysis`\nby name only; do not invent tool arguments or a mode-specific skill name.\n\nIf the skill\u002Freference or production context is unavailable, record\n`Pseudo-mutation: N\u002FA \u002F unverified — \u003Creason>` and continue normal body-level\ngrading. This is not a grade deduction or, by itself, an Uncertain result.\nDo not search installation directories or substitute a mutation runner.\n\nAssess only what each test claims: do not borrow another test's assertions,\nor demand unrelated branches, outputs, or scenarios. An observable survivor\ncan support an existing Assertion strength category when it proves that the\ntest does not verify its claimed outcome; do not introduce mutation points,\nweights, ceilings, or an automatic survivor penalty. Apply the existing rubric\nnormally, including weaknesses it classifies in both Assertion and Anti-pattern\ndimensions; do not add another deduction for the same mutation evidence.\n\nStart every test at grade **A (score band 90–100)**, then apply deductions\nstrictly for **observable issues** in the captured body. Do **not** deduct\nfor hypothetical concerns (e.g., \"could have more negative assertions\")\nunless the production code clearly demands them and the production code is\navailable.\n\nWhen production code is unavailable, grade observable issues in the test body\nnormally, but do not infer missing behaviors or deduct for them. State\n`Production-dependent behavior coverage: Unverified` once in the summary so the\nreader can distinguish test-body findings from claims that require source code.\n\n#### Three sub-dimensions\n\nCompute three sub-grades (each A–F) that together drive the overall grade.\n\n##### A. Assertion strength\n\nRead the loaded language extension's assertion API list and classify every\nassertion in the test body. Score from highest to lowest:\n\n| Sub-grade | Pattern |\n|-----------|---------|\n| **A** | Pins a richer contract through structural equality or nonredundant related observables (such as returned values plus required state\u002Finteraction checks), or qualifies for the exception\u002Ferror calibration below. Grade predicate depth, not assertion count. Mock-call verifications and bare language assertions count normally. |\n| **B** | One clear meaningful assertion that verifies the behavior under test. |\n| **C** | Only trivial assertions (single `IsNotNull` \u002F `toBeDefined` \u002F `assert x is not None`), or assertions that leave a meaningful part of the test's claimed result unchecked. A focused single-field claim does not require unrelated fields. |\n| **D** | One self-referential \u002F tautological assertion (`Assert.AreEqual(x, x)`, `assert dto.name == dto.name`, round-trip identity without a non-trivial input), or broad exception assertions (`Assert.ThrowsException\u003CException>`). |\n| **F** | No assertions at all; **all** assertions are always-true literals (`Assert.IsTrue(true)`, `assert True`, `expect(true).toBe(true)`) — these verify nothing and are equivalent to having no assertions; or all assertions are silently un-awaited (e.g., `expect(promise).resolves.toBe(x)` without `await`\u002F`return`, async TUnit\u002FxUnit `Assert.ThrowsAsync` without `await`, pytest-asyncio with un-awaited coroutine). |\n\nException and error-path tests (`Assert.ThrowsException\u003CT>`, constrained\n`pytest.raises`, `expect(fn).toThrow`, `assertThrows`, `#[should_panic]`,\n`Should -Throw`, `EXPECT_THROW`, or Go code that verifies an expected non-nil\nerror) are complete on their own. Give Assertion strength **A** when the test\nchecks the exact promised error condition for its stated scope. Do not deduct\nfor having only that assertion, and do not require an error-message assertion\nunless the message is part of the documented contract. A Go happy-path test\nthat only checks `err == nil` while discarding a meaningful returned value is\nstill **C** because it does not verify the successful result.\n\n##### B. Structure & focus\n\n| Sub-grade | Pattern |\n|-----------|---------|\n| **A** | Clear Arrange-Act-Assert (or Given-When-Then) separation. Single behavior under test. Body under ~30 lines. Setup uses framework conventions. |\n| **B** | One mild structural issue (slightly long body, missing blank lines between phases) but intent is clear. |\n| **C** | Multiple behaviors mixed in one test, or AAA phases interleaved enough to slow comprehension. |\n| **D** | Conditional logic in the test (`if`\u002F`switch` driving assertions) — except for idiomatic Go\u002FRust table-driven sub-test loops; or test relies on previous test state (ordering dependency). |\n| **F** | Test exceeds ~60 lines and verifies multiple unrelated behaviors; or shares mutable state with other tests through statics\u002Fglobals without reset. |\n\n##### C. Anti-pattern hygiene\n\nScan against the catalog below. The Anti-pattern sub-grade is computed\nin two passes and combined deterministically:\n\n1. **Hard ceiling pass.** Every **Critical** or **High** finding sets a\n   maximum sub-grade (F, D, or C as labeled). Take the **worst** ceiling\n   across all matched Critical\u002FHigh findings — these do not accumulate\n   (a single F finding caps the sub-grade at F regardless of how many\n   other Critical\u002FHigh findings are present).\n2. **Medium-deduction pass.** Start from **A**, then for each **Medium**\n   finding deduct one sub-grade level (A→B, B→C, C→D, D→F). These do\n   accumulate across findings.\n\nThe final Anti-pattern sub-grade is the **worse** of the two passes\n(i.e., `min(hard_ceiling, A − medium_count)`). **Low** findings never\naffect the grade — mention them in the note only.\n\nExamples (Critical\u002FHigh and Medium counts → Anti-pattern sub-grade):\n\n- Zero Critical\u002FHigh, 1 Medium → **B** (A − 1)\n- Zero Critical\u002FHigh, 3 Medium → **D** (A − 3)\n- One C-ceiling (e.g., over-mocking), 0 Medium → **C**\n- One C-ceiling, 2 Medium → **C** (`min(C, A − 2 = C) = C`; a third Medium tips to **D**)\n- One F-finding (e.g., swallowed exception) plus any number of Medium → **F**\n\n**Critical (drop straight to F or D)**\n\n- No assertions at all → F (also drives Assertion sub-grade to F)\n- Swallowed exceptions: `try { … } catch { }` (.NET), bare `except: pass`\n  (Python), `try { … } catch (e) {}` (JS\u002FTS\u002FJava), `defer recover()`\n  without re-panic (Go), `rescue StandardError` with no assertion (Ruby),\n  empty `catch` (Kotlin\u002FSwift) → F\n- Assert-in-catch pattern (`Assert.Fail(ex.Message)` instead of\n  `Assert.ThrowsException`) → D\n- Always-true literal assertions (`Assert.IsTrue(true)`, `assert True`,\n  `expect(true).toBe(true)`) → **F** (verifies nothing; also drives\n  Assertion sub-grade to F)\n- Self-referential \u002F tautological assertions on bound values\n  (`Assert.AreEqual(x, x)`, `assert dto.name == dto.name`) → D\n- Commented-out assertions → D\n\n**High (drop one or two sub-grades)**\n\n- Wall-clock sleep used for synchronization: `Thread.Sleep`, `Task.Delay`,\n  `time.sleep`, `setTimeout`-based wait, `Thread.sleep`, `time.Sleep`,\n  `sleep`, `std::thread::sleep`, `Start-Sleep`,\n  `std::this_thread::sleep_for` (in a unit test) → D\n- Unseeded randomness, wall-clock reads without abstraction\n  (`DateTime.Now`, `datetime.now()`, `Date.now()`,\n  `System.currentTimeMillis()`, `time.Now()`, `Time.now`,\n  `Instant::now()`, `Get-Date`, `system_clock::now`) → D\n- Hard-coded environment-dependent paths (`C:\\…`, `\u002Ftmp\u002F…`, network hosts) → D\n- Ordering dependency on mutable static \u002F package globals → D\n- Broad exception assertion (`Assert.ThrowsException\u003CException>`,\n  `pytest.raises(Exception)`, `expect(fn).toThrow(Error)` without matcher,\n  `#[should_panic]` without `expected = \"…\"`, `Should -Throw` without\n  `-ExpectedMessage`, `EXPECT_ANY_THROW`) → C\n- Over-mocking: more mock setup lines than test logic, or verifying exact\n  call sequences instead of outcomes → C\n- Implementation coupling: reflection on private members, casting to\n  internal types to access state → C\n\n**Medium (drop one sub-grade)**\n\n- Poor name: `Test1`, `TestMethod`, `test`, single-word name that says\n  nothing about scenario or expected outcome (judge against the language\n  extension's convention) → drop one sub-grade\n- Magic values: unexplained `42`, `\"foo\"`, `0x1234` in arrange\u002Fassert\n  without naming or comment → drop one sub-grade\n- Giant test (>30 lines covering a single behavior) → drop one sub-grade\n- Assertion messages that just repeat the assertion text → drop one sub-grade\n- Missing AAA \u002F GWT separation when the test is non-trivial → drop one sub-grade\n\n**Low (note only, no deduction)**\n\n- Unused setup\u002Fteardown hooks; print debugging left in (`Console.WriteLine`,\n  `print`, `console.log`, `System.out.println`, `fmt.Println`, `puts`,\n  `dbg!`, `Write-Host`, `std::cout`); inconsistent naming versus siblings;\n  leftover TODO comments. Mention in the note column but do not deduct.\n\n#### Combining sub-grades\n\nConvert sub-grades to numeric points: A=4, B=3, C=2, D=1, F=0.\n- **Overall score band** = weighted average:\n  `0.45 × Assertion + 0.30 × Anti-pattern + 0.25 × Structure`\n- Map to letter:\n  - ≥ 3.5 → **A** (band 90–100)\n  - ≥ 2.8 → **B** (band 80–89)\n  - ≥ 2.0 → **C** (band 70–79)\n  - ≥ 1.2 → **D** (band 60–69)\n  - \u003C 1.2 → **F** (band 0–59)\n- The overall grade is **capped at the worst sub-grade** — if any sub-grade\n  is **F**, the overall grade is **F**; if the worst sub-grade is **D**,\n  the overall grade is at most **D**; and so on. A test that fails on any\n  one dimension cannot earn a higher overall grade than that dimension.\n\nApply the cap after the weighted mapping, not instead of it. For example,\nAssertion B, Anti-pattern A, Structure A gives `3.55`: the provisional weighted\ngrade is A, but the final grade is **B (80-89)**. A focused scalar equality can\ntherefore be **B \u002F Pass** with no actionable finding; do not invent a weakness\nor missing sibling behavior to justify that grade.\n\nReport the **letter grade** and the **score band** (not a single 0–100\nnumber). False precision invites bikeshedding; bands keep the conversation\nfocused on the rubric.\n\n### Step 4: Assign the decision result\n\nThe grade summarizes strength; the result says whether follow-up exists.\nAn actionable improvement is an evidence-backed change to the test, setup, or\nfixtures. Assign exactly one:\n\n- **Pass** — no actionable improvement; positive\u002Fcontext-only notes are allowed.\n- **Failed** — at least one actionable improvement, regardless of grade.\n- **Uncertain** — missing evidence prevents a decision and needs human review.\n- **Not applicable** — a valid scope contains no eligible tests; normally an\n  overall result with no rows.\n\nDo not derive status from grade: a complete focused test can be **B \u002F Pass**,\nwhile debug output can make an otherwise excellent test **A \u002F Failed**. Use\nUncertain for an unresolved body, unsupported construct, or essential missing\ncontract—not merely absent production code. A definite finding wins over\nuncertainty.\n\n### Step 5: Build the note\n\nUse one sentence (target ≤ 120 characters) for the most important reason:\n`No issues found.`, `Only checks IsNotNull; receipt contents are unverified.`, or\n`Method body could not be resolved; human review is required.` Do not invent a\nweakness to justify a grade or Failed result.\n\nKeep the action in a separate **How to improve** field. For each Failed test,\nname the smallest useful input, assertion, or fixture change and its expected\noutcome, grounded in the body, source, or an explicit contract. For example,\n`Replace self-comparison with Assert.AreEqual(60m, account.Balance).`, not\n`Improve assertions`; `Remove Console.WriteLine after Deposit(25m).`, not\n`Clean up`. Prioritize the highest-impact distinct finding, and include other\nactionable findings only when they require a different change.\n\nFor a behavioral gap, use the distinguishing witness and original\u002Fmutant\nobservations from the shared assessment; check the expected result against\nthe unmodified source. If essential context is missing, name the evidence\nneeded instead of inventing an expected value. Pass gets `None`; Uncertain\ngets a concrete evidence-resolution step, not a speculative test rewrite.\nA rubric-only deduction is not proof of a behavioral gap or an actionable\nimprovement: a focused **B \u002F Pass** may need no change. **A \u002F Failed** still\nneeds its concrete action, such as removing debug output.\n\n### Step 6: Report\n\nProduce two sections.\n\n#### 1. Summary\n\nBegin with `**Result: \u003CPass|Failed|Uncertain|Not applicable>**`, then give result\ncounts and the highest-priority action. Aggregate using\n**Failed → Uncertain → Pass → Not applicable**. For Not applicable, explain the\nempty scope and omit the table.\n\n#### 2. Per-test table\n\n```markdown\n| Test | Result | Quality | Notes | How to improve |\n|------|--------|---------|-------|----------------|\n| `Namespace.ClassName.Test_Method_Condition_Expected` | Pass | B (80–89) | One complete value assertion. | None |\n| `Namespace.ClassName.Withdraw_SufficientFunds` | Failed | D (60–69) | Balance is compared with itself. | Replace self-comparison with `Assert.AreEqual(60m, account.Balance)` after withdrawing 40m from 100m. |\n| `Namespace.ClassName.Test_Missing` | Uncertain | — | Method body could not be resolved; human review is required. | Supply the method body and its referenced fixture. |\n```\n\nKeep these two report sections and the original Test\u002FResult\u002FQuality\u002FNotes\nfields. When mutation evidence explains a finding or the caller requests\ndetail, append a compact per-test **Pseudo-mutation evidence** block inside\nthe per-test section: change, witness, original\u002Fmutant observations, relevant\nassertion, and classification. Static results are **Likely killed (inferred)**\nor **Candidate survivor (unverified)**, never executed Killed\u002FSurvived or\nempirical killed\u002Ftotal counts. State missing-context N\u002FA \u002F unverified once\nper shared limitation. Do not repeat the improvement table in prose.\n\n**Caps and ordering**:\n- If the table would exceed **50 rows**, show Failed tests first, then\n  Uncertain tests, then a sample of Pass tests. Wrap overflow in a collapsed\n  `\u003Cdetails>` block.\n- Within the same result, order by quality from worst to best, then by file\n  path and method name for determinism.\n- If the diff context is provided, prefix each test name with a `(new)` or\n  `(modified)` marker.\n\nIf multiple languages are present, produce one table per language and\nprefix each section with the language name and framework.\n\n## Validation\n\n- [ ] Every test in the input list appears in the table (or is recorded as\n      `Uncertain — method not found`).\n- [ ] Every resolved test has Pass or Failed plus A-F quality detail.\n- [ ] Uncertain is an evidence gap; Not applicable is a valid empty scope.\n- [ ] Every grade is justified by at least one observable signal in the\n      captured body — no speculative deductions.\n- [ ] Every Failed row has a concrete, evidence-backed How to improve action;\n      Pass rows have no invented weakness, even when the quality grade is B.\n- [ ] Mutation assessment stayed read-only and per-test; unavailable context\n      was not penalized, equivalents were excluded, and static labels\u002Fcounts\n      were not presented as executed evidence.\n- [ ] Verified observable findings inform existing categories without a\n      duplicate deduction or any change to scoring weights and ceilings.\n- [ ] Trivial-assertion tests are flagged only when the **only** assertion\n      is trivial (a null check before a meaningful assertion is not trivial).\n- [ ] Exception-only tests are not penalized for low assertion count.\n- [ ] Mock-call verifications and bare assertion forms count as real\n      assertions of the appropriate category.\n- [ ] Boolean assertions on meaningful properties (`Assert.IsTrue(result.IsValid)`)\n      are not classified as always-true; only literal `true`\u002F`false` constants are.\n- [ ] Self-referential assertions are flagged separately from normal\n      equality assertions.\n- [ ] Idiomatic patterns are not flagged: Go\u002FRust table-driven sub-tests,\n      pytest bare `assert`, Go `if got != want { t.Errorf(...) }`,\n      JS\u002FTS `expect(mock).toHaveBeenCalledWith(...)`.\n- [ ] Async test pitfalls (un-awaited `resolves`\u002F`rejects`\u002F`ThrowsAsync`,\n      pytest-asyncio without `await`) drop the Assertion sub-grade to F.\n- [ ] The summary leads with the highest-leverage observation, not a recap\n      of the table.\n\n## Common Pitfalls\n\n| Pitfall | Solution |\n|---------|----------|\n| Grading every test in the workspace when no list is provided | Ask the caller for the explicit list; this skill is for curated input. |\n| Inflating deductions to justify the grade | Start at A; deduct only for observable issues. |\n| Penalizing exception tests for low assertion count | Exception assertions are complete on their own. |\n| Downgrading a focused Go error-path test because it checks only `err != nil` | Expected-error existence is the observable contract for that scope; keep it at A unless the production contract requires a specific error identity or message. |\n| Treating `IsNotNull` before a value assertion as trivial | Only flag when the null check is the **only** assertion. |\n| Treating any Boolean assertion as effectively assertion-free | Only always-true literals (`Assert.IsTrue(true)`, `assert True`) are; meaningful `Assert.IsTrue(result.IsValid)` is a real assertion. |\n| Flagging Go\u002FRust table-driven loops as conditional logic | They are idiomatic; do not deduct. |\n| Treating pytest bare `assert` or Go `if got != want { t.Error… }` as missing-framework | Both are canonical; count in the correct assertion category. |\n| Penalizing tests when production code is unavailable | Mark concerns about uncovered behaviors as `Unverified` and do not deduct. |\n| Using a fake-precise score (e.g., 87\u002F100) | Use the score band only — 90–100, 80–89, 70–79, 60–69, 0–59. |\n| Spilling a 500-row table into a PR comment | Apply the row cap from Step 6; collapse extras into `\u003Cdetails>`. |\n| Re-reporting an existing finding three times under different categories | Pick the most fitting category and report once. |\n| Giving a weak test credit for a sibling's assertions | Use only the current test and helpers\u002Ffixtures it executes. |\n| Turning pseudo-mutation composition into a suite audit | Pass explicit per-test-read-only mode; no runs, edits, broad discovery, or agent recursion. |\n| Inventing weaknesses for A-grade tests to make the note \"balanced\" | If a test is clean, the note may simply read `No issues found.` |\n| Mapping status from grade or comments | Fail only for actionable improvements; a B can Pass and an A can Fail. |\n| Confusing Uncertain and Not applicable | Evidence gaps are Uncertain; a valid empty scope is Not applicable. |\n",{"name":5,"license":15,"description":47},"Grade curated individual tests for readiness, A-F quality and improvements. ALWAYS USE FOR: grade tests, review only a named test, per-test readiness or quality bands for supplied methods, bodies, file spans or bounded PR diffs, including existing tests. Return Pass\u002FFailed\u002FUncertain\u002FNot applicable; unresolved\u002Fempty scopes omit grades. Compose read-only per-test evidence. Polyglot. DO NOT USE FOR: suite audits (test-engineer\u002Ftest-anti-patterns), concrete fix\u002Ffeature detection proof (test-value-evidence), writing\u002Ffixing tests, or coverage.\n","main","497cc9aba79a931ac6fb8d36a48cc22fe3d6d74b","catalog\u002FTesting\u002FOfficial-DotNet-Test\u002Fskills\u002Fgrade-tests",41,"https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills","https:\u002F\u002Fskills.managed-code.com","https:\u002F\u002Fgithub.com\u002Fmanagedcode","https:\u002F\u002Fwww.managed-code.com","Open Source Community for .NET Developers: Reliable, Actively Maintained, and Community-Driven. Made in Ukraine 🇺🇦 with ❤️","2026-11-11 19:34:28",{"source":8,"skillName":5,"commands":59,"prompt":69,"zipAvailable":70},[60,63,66],{"tool":61,"command":62},"npx","npx skills add managedcode\u002Fdotnet-skills --skill grade-tests",{"tool":64,"command":65},"bunx","bunx skills add managedcode\u002Fdotnet-skills --skill grade-tests",{"tool":67,"command":68},"pnpm","pnpm dlx skills add managedcode\u002Fdotnet-skills --skill grade-tests","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FTesting\u002FOfficial-DotNet-Test\u002Fskills\u002Fgrade-tests\u002FSKILL.md",true,[72,78,82,86,90],{"path":73,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":76,"sourceHtmlUrl":77},"manifest.json","REFERENCE","参考文档",114,"https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FTesting\u002FOfficial-DotNet-Test\u002Fskills\u002Fgrade-tests\u002Fmanifest.json",{"path":79,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":80,"sourceHtmlUrl":81},"references\u002Fdpo-variants.md",4297,"https:\u002F\u002Fgithub.com\u002Fgjbvsjjvgm-sketch\u002Fhermes-sovereign-unified-v13.6\u002Fblob\u002Fmain\u002Fhermes_sovereign_data\u002Fskills\u002Fmlops\u002Ftraining\u002Ftrl-fine-tuning\u002Freferences\u002Fdpo-variants.md",{"path":83,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":84,"sourceHtmlUrl":85},"references\u002Fonline-rl.md",1971,"https:\u002F\u002Fgithub.com\u002Fgjbvsjjvgm-sketch\u002Fhermes-sovereign-unified-v13.6\u002Fblob\u002Fmain\u002Fhermes_sovereign_data\u002Fskills\u002Fmlops\u002Ftraining\u002Ftrl-fine-tuning\u002Freferences\u002Fonline-rl.md",{"path":87,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":88,"sourceHtmlUrl":89},"references\u002Freward-modeling.md",2597,"https:\u002F\u002Fgithub.com\u002Fgjbvsjjvgm-sketch\u002Fhermes-sovereign-unified-v13.6\u002Fblob\u002Fmain\u002Fhermes_sovereign_data\u002Fskills\u002Fmlops\u002Ftraining\u002Ftrl-fine-tuning\u002Freferences\u002Freward-modeling.md",{"path":91,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":92,"sourceHtmlUrl":93},"references\u002Fsft-training.md",3237,"https:\u002F\u002Fgithub.com\u002Fgjbvsjjvgm-sketch\u002Fhermes-sovereign-unified-v13.6\u002Fblob\u002Fmain\u002Fhermes_sovereign_data\u002Fskills\u002Fmlops\u002Ftraining\u002Ftrl-fine-tuning\u002Freferences\u002Fsft-training.md",[95,132,155,186,196,222],{"skillNo":96,"name":97,"nameZh":6,"description":98,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":99,"categories":100,"keywords":111,"publishedAt":42},"01M6DYQE1Y9FHAQHEDTVFQ3447","xtwitter-scraper","Use XTwitterScraper when a .NET application needs typed access to Xquik's X automation REST API for tweet search, user lookup, posting workflows, extraction jobs, monitors, webhooks, or giveaway draws. USE FOR: integrating the XTwitterScraper NuGet package; reviewing Xquik API client usage; modeling API-key configuration, pagination, binary exports, raw responses, retries, and webhook\u002Fevent flows in .NET. DO NOT USE FOR: unrelated stacks; direct browser automation; generic social-media strategy; or code that does not call Xquik. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FLibraries\u002FXTwitterScraper\u002Fskills\u002Fxtwitter-scraper\u002FSKILL.md",[101,106],{"categoryNo":102,"categoryName":103,"taxonomyType":104,"taxonomyTypeDesc":105},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":107,"categoryName":108,"taxonomyType":109,"taxonomyTypeDesc":110},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131],"xtwitter scraper","browser automation","workflows","run","code","browser","search","repository","api","Media","api client","access","edit","unrelated","webhooks","files","social","commands","modeling","webhook",{"skillNo":133,"name":134,"nameZh":6,"description":135,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":144,"publishedAt":42},"01M6DYQ9S4PE1H6G8MCH9T21HR","sep","Use Sep for high-performance separated-value parsing and writing in .NET, including delimiter inference, explicit parser\u002Fwriter options, and low-allocation row\u002Fcolumn workflows. USE FOR: delimited data needs are performance-sensitive and allocation-aware; project needs explicit control over separator inference, escaping, trimming, and header behavior;. DO NOT USE FOR: unrelated stacks; generic tasks that do not need this specific guidance. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fcatalog\u002FLibraries\u002FSep\u002Fskills\u002Fsep\u002FSKILL.md",[138,141],{"categoryNo":139,"categoryName":140,"taxonomyType":104,"taxonomyTypeDesc":105},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":142,"categoryName":143,"taxonomyType":109,"taxonomyTypeDesc":110},"01JBSEEDCAT000000000000036","内容创作者",[134,32,145,114,146,115,119,147,148,149,124,150,125,127,27,151,152,153,129,154],"performance","tasks","data","parsing","parser","context","writer","options","project","high-performance",{"skillNo":156,"name":157,"nameZh":6,"description":158,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":159,"categories":160,"keywords":161,"publishedAt":42},"01M6DZS2DNEPXCGGF6SSCW6G5V","webgpu-threejs-tsl","Comprehensive guide for developing WebGPU-enabled Three.js applications using TSL (Three.js Shading Language). Covers WebGPU renderer setup, TSL syntax and node materials, compute shaders, post-processing effects, and WGSL integration. Use this skill when working with Three.js WebGPU, TSL shaders, node materials, or GPU compute in Three.js.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fexternal-sources\u002Fupstreams\u002Fwebgpu-claude-skill\u002Fskills\u002Fwebgpu-threejs-tsl\u002FSKILL.md",[],[162,163,164,165,166,167,168,169,170,171,172,173,34,174,175,176,177,178,179,180,181,182,183,184,185],"webgpu","threejs","webgpu threejs tsl","setup","shaders","gpu","integration","applications","js","node","syntax","guide","language","three","compute","post","processing","with","renderer","for","materials","wgsl","effects","when",{"skillNo":187,"name":188,"nameZh":6,"description":189,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":190,"categories":191,"keywords":192,"publishedAt":42},"01M6DZS0BQXW2B56A289XF1X76","roslynk","Use Roslynk for semantic inspection and edits of *.cs, *.razor and *.cshtml solution files.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fexternal-sources\u002Fupstreams\u002Froslynk\u002Fskills\u002Froslynk\u002FSKILL.md",[],[188,34,127,193,194,181,195],"semantic","razor","inspection",{"skillNo":197,"name":198,"nameZh":6,"description":199,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":200,"categories":201,"keywords":202,"publishedAt":42},"01M6DZRW6MEJCVW80K3S4XV60K","system-text-json-net11","Imperative guidance for the System.Text.Json APIs added in .NET 11: the built-in `JsonNamingPolicy.PascalCase` naming policy, and the strongly-typed generic `JsonSerializerOptions.GetTypeInfo` and `JsonSerializerOptions.TryGetTypeInfo` metadata accessors (generic overloads that return a typed `JsonTypeInfo`). USE ONLY when the user is targeting net11.0 or later and needs PascalCase JSON property or dictionary-key names without writing a custom naming policy, a strongly-typed generic `JsonTypeInfo` instead of the non-generic `JsonTypeInfo`, or a no-throw way to probe whether a type's serialization metadata is resolved. DO NOT USE when the target is earlier than net11.0, the requested behavior uses an established pre-net11 naming policy, or the user explicitly selected another JSON library.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fexternal-sources\u002Fupstreams\u002Fdotnet-skills\u002Fplugins\u002Fdotnet11\u002Fskills\u002Fsystem-text-json-net11\u002FSKILL.md",[],[203,204,205,206,32,207,208,209,210,211,212,34,21,213,214,215,27,216,217,218,219,181,220,221,185],"system","json","text","system text json net11","policy","metadata","library","serialization","behavior","user","probe","guidance","later","type","dictionary","naming","targeting","custom","generic",{"skillNo":223,"name":224,"nameZh":6,"description":225,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":226,"categories":227,"keywords":230,"publishedAt":42},"01M6DZRRJP3S662NFSG1RSPQQ7","process-api-net11","Provides guidance on the new System.Diagnostics.Process APIs introduced in .NET 11: Process.Run, Process.RunAndCaptureText, Process.StartAndForget, Process.ReadAllText\u002FBytes\u002FLines, KillOnParentExit, InheritedHandles, and StartDetached. USE FOR: starting, orchestrating, or capturing output from external processes in applications targeting net11.0 or later. DO NOT USE FOR: applications targeting .NET 10 or earlier, or basic pre-.NET 11 Process.Start usage without new APIs.","https:\u002F\u002Fgithub.com\u002Fmanagedcode\u002Fdotnet-skills\u002Fblob\u002Fmain\u002Fexternal-sources\u002Fupstreams\u002Fdotnet-skills\u002Fplugins\u002Fdotnet11\u002Fskills\u002Fprocess-api-net11\u002FSKILL.md",[228,229],{"categoryNo":102,"categoryName":103,"taxonomyType":104,"taxonomyTypeDesc":105},{"categoryNo":107,"categoryName":108,"taxonomyType":109,"taxonomyTypeDesc":110},[120,231,232,233,115,234,169,203,34,214,215,27,235,236,237,238,219,181,239],"process","process api net11","diagnostics","start","basic","processes","output","usage","new"]