[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-dotnet-find-untested-sources":3,"mdc-754tu7-key":34,"related-org-dotnet-find-untested-sources":2242,"related-repo-dotnet-find-untested-sources":2402},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":22,"repoUrl":23,"updatedAt":24,"license":25,"forks":26,"topics":27,"repo":29,"sourceUrl":32,"mdContent":33},"find-untested-sources","identify untested source files","MANDATORY for static requests to find, identify, or list untested source files or modules, sources without tests, source-to-test pairing, test-gap worklists, or suggested test locations. Invoke even for a tiny package; do not substitute manual globbing. Uses Roslyn for C#\u002F.NET and tree-sitter for Python, TS\u002FJS, Go, Java, Rust, and Ruby. DO NOT USE FOR: line\u002Fbranch coverage, CRAP risk, or grading existing tests.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"dotnet",".NET (Microsoft)","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fdotnet.png",[12,16,19],{"name":13,"slug":14,"type":15},".NET","net","tag",{"name":17,"slug":18,"type":15},"Code Analysis","code-analysis",{"name":20,"slug":21,"type":15},"Testing","testing",4576,"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills","2026-07-25T05:31:26.31545","MIT",332,[28],"agent-skills",{"repoUrl":23,"stars":22,"forks":26,"topics":30,"description":31},[28],"Repository for skills to assist AI coding agents with .NET and C#","https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills\u002Ftree\u002FHEAD\u002Fplugins\u002Fdotnet-test\u002Fskills\u002Ffind-untested-sources","---\nname: find-untested-sources\ndescription: >\n  MANDATORY for static requests to find, identify, or list untested source files\n  or modules, sources without tests, source-to-test pairing, test-gap worklists,\n  or suggested test locations. Invoke even for a tiny package; do not substitute\n  manual globbing. Uses Roslyn for C#\u002F.NET and tree-sitter for Python, TS\u002FJS, Go,\n  Java, Rust, and Ruby. DO NOT USE FOR: line\u002Fbranch coverage, CRAP risk, or\n  grading existing tests.\nlicense: MIT\n---\n\n# Find Untested Sources\n\n## Purpose\n\nCoverage tools answer \"which lines were executed?\" — they require a green build\nand a passing test run, which is minutes-to-tens-of-minutes on a real repo. The\nquestion this skill answers is different and much cheaper:\n\n> _Which source files have no test file referencing any of their declared\n> types\u002Fsymbols?_\n\nThat's the question an agent asks **before** writing a new test — and it can be\nanswered statically in a few seconds by parsing source files, with **no build,\nno dependency resolution, and no compilation**. The output is a deterministic\ntest-pairing map that lets the agent pick the next file to test without reading\nthe entire codebase first.\n\n## Two engines — pick one\n\nThis skill ships two interchangeable analyzers with a compatible JSON contract:\n\n| Engine | Script | Use when |\n|--------|--------|----------|\n| **Roslyn (C#)** | `scripts\u002FFind-UntestedSources.cs` | The repo is **.NET-only**. Parses every `.cs` file with the Roslyn syntax API and does strict **namespace disambiguation**, so it is materially more accurate on duplicated short names like `Settings` or `Context`. |\n| **tree-sitter (polyglot)** | `scripts\u002Ffind_untested_sources.py` | The repo is **not exclusively C#**, or you want one tool across Python, TypeScript\u002FJavaScript, Go, Java, Rust, Ruby, and C#. |\n\nFor a .NET-only repository, **prefer the Roslyn engine** — its namespace-aware\npairing beats the polyglot engine's identifier overlap.\n\n## Required workflow\n\n1. Use the narrowest repository or package root named by the caller. Do not scan\n   a parent workspace when the request identifies a subdirectory.\n2. Execute the appropriate analyzer once. Do not replace analyzer execution with\n   manual globbing, filename matching, or visual inspection.\n   For polyglot analysis, pass `--include-tested` when the answer must distinguish\n   paired sources from unpaired sources.\n3. Base the result on the analyzer's JSON. Preserve its paired\u002Funpaired\n   classification and suggested relative path; do not guess a different path.\n4. When the caller named a subdirectory, prefix analyzer-relative paths with\n   that subdirectory so reported paths are workspace-relative.\n5. Report the requested result plus the static-pairing coverage caveat. Do not\n   append build, package-install, test-run, or coverage commands. When paired\n   sources exist, name their covering test files so the unpaired classification\n   is auditable.\n\n## When to Use\n\n- User asks \"where should I add tests?\", \"which files have no tests?\", \"find\n  untested code\", \"give me a test gap list\", \"what's the next file to test\".\n- Before invoking a test-generation agent, to produce a prioritized worklist.\n- After generating tests, to verify each new test file pairs to a source file.\n- To enumerate \"weakly paired\" source files (only one referring test) for\n  follow-up depth checks.\n\n## When Not to Use\n\n- **Line\u002Fbranch coverage** — use `coverage-analysis`.\n- **CRAP-score \u002F risk hotspots** — use `coverage-analysis`.\n- **Are existing tests strong?** — use `test-gap-analysis` (mutation reasoning)\n  or `assertion-quality`.\n\n## Roslyn engine (C#)\n\n### Prerequisites\n\n- .NET SDK that supports file-based apps (`dotnet run script.cs`). Pinned in the\n  repo's `global.json` (SDK 11 preview or later).\n- No internet access required beyond the initial NuGet restore of\n  `Microsoft.CodeAnalysis.CSharp` on first run.\n\n### Usage\n\n```powershell\n# From the skill folder\ndotnet run scripts\u002FFind-UntestedSources.cs -- \u003Crepo-root> [--top N]\n\n# Save the report\ndotnet run scripts\u002FFind-UntestedSources.cs -- \u003Crepo-root> > pairing.json\n\n# Iterate the untested list, highest-API-surface first\n$report = Get-Content pairing.json | ConvertFrom-Json\n$report.untested | Select-Object -First 10 source, decl_count, suggested_test_path\n```\n\nDiagnostics go to stderr; JSON goes to stdout.\n\n### Output schema\n\n```jsonc\n{\n  \"repo\": \"\u003Cabsolute path>\",\n  \"elapsed_ms\": 8883,\n  \"counts\": {\n    \"source_files\": 3036,\n    \"test_files\": 867,\n    \"untested_files\": 1852,\n    \"paired_files\": 1184\n  },\n  \"untested\": [\n    {\n      \"source\": \"src\u002FFoo\u002FBar.cs\",\n      \"decl_count\": 8,            \u002F\u002F # of type declarations in the file\n      \"suggested_test_path\":      \u002F\u002F mirror of source under a discovered test project\n        \"tests\u002FFoo.Tests\u002FBar\u002FBarTests.cs\"\n    }\n  ],\n  \"source_to_tests\": {\n    \"src\u002FFoo\u002FBaz.cs\": [\n      \"tests\u002FFoo.Tests\u002FBazTests.cs\",\n      \"tests\u002FFoo.IntegrationTests\u002FScenarios\u002FBazScenarios.cs\"\n    ]\n  }\n}\n```\n\n### How it works\n\n1. **File discovery** — recursive walk pruning `bin\u002F`, `obj\u002F`, `node_modules\u002F`,\n   `.git\u002F`, `.vs\u002F`, `packages\u002F`, and any dotted subdir. Skips generated files\n   (`.g.cs`, `.Designer.cs`, `.AssemblyInfo.cs`).\n2. **Test vs source classification** — walks up to the nearest `.csproj` and\n   marks it a test project if the project name ends in `.Tests`, `.Test`,\n   `.UnitTests`, `.IntegrationTests`, `.E2E`, `.EndToEnd`, `.Spec`, `.Specs`, or\n   the content references `Microsoft.NET.Test.Sdk`, `MSTest.Sdk`,\n   `Microsoft.Testing.Platform`, `xunit`, `NUnit`, `TUnit`, or\n   `\u003CIsTestProject>true\u003C\u002FIsTestProject>`.\n3. **Source index (parallel)** — parse each source file with\n   `CSharpSyntaxTree.ParseText` (syntax only, no compilation); record every\n   `BaseTypeDeclarationSyntax` \u002F `DelegateDeclarationSyntax` as\n   `(ShortName, EnclosingNamespace, FilePath)`.\n4. **Test scan (parallel)** — parse each test file, collect `using` directives +\n   enclosing namespace, walk every `IdentifierToken`, look it up in the\n   short-name index, and **disambiguate strictly**: an identifier is attributed\n   only if the declaration's namespace matches one of the test file's `using`\n   directives, the enclosing namespace, or a prefix of them. This avoids noise\n   where common names like `Settings` or `Context` match every project.\n5. **Pairing & suggestion** — invert into `source → [tests]`. Build a\n   production-to-test project map from `\u003CProjectReference>` entries; for each\n   untested source, mirror its in-project relative path under the referencing\n   test project to suggest a path.\n6. **JSON emit** — ordered by declaration count desc, then alphabetical.\n\n## Polyglot engine (tree-sitter)\n\n### Prerequisites\n\n- Python 3.10+.\n- `pip install tree-sitter-language-pack` (single self-contained wheel that\n  bundles parsers for 300+ languages and the high-level `process()` API). No\n  native build, no per-language grammar install.\n\n### Usage\n\n```powershell\n# From the skill folder\npython scripts\u002Ffind_untested_sources.py \u003Crepo-root>\n\n# Restrict to a language (repeatable)\npython scripts\u002Ffind_untested_sources.py \u003Crepo-root> --lang python --lang typescript\n\n# Truncate the report (top 20 by declared API surface)\npython scripts\u002Ffind_untested_sources.py \u003Crepo-root> --limit-untested 20 > pairing.json\n\n# Iterate, highest-API-surface first\n$report = Get-Content pairing.json | ConvertFrom-Json\n$report.untested_sources | Select-Object -First 10 path, declaration_count, suggested_test_path\n```\n\nPass `--include-tested` to additionally emit `tested_sources` (omitted by\ndefault to keep the payload small for LLM consumption). Diagnostics go to\nstderr; JSON goes to stdout.\n\n### Output schema\n\n```jsonc\n{\n  \"repo_root\": \"\u003Cabsolute path>\",\n  \"summary\": {\n    \"source_files\": 3138,\n    \"test_files\": 761,\n    \"tested_source_files\": 1419,\n    \"untested_source_files\": 1719,\n    \"orphan_test_files\": 15,\n    \"languages\": [\"csharp\"]\n  },\n  \"untested_sources\": [\n    {\n      \"path\": \"src\u002FFoo\u002FBar.cs\",\n      \"language\": \"csharp\",\n      \"declaration_count\": 8,\n      \"declarations\": [\"Bar\", \"BarOptions\", \"IBar\", \"...\"],\n      \"suggested_test_path\": \"src\u002FFoo\u002FBarTests.cs\"\n    }\n  ],\n  \"orphan_tests\": [\n    { \"path\": \"tests\u002FSomeIntegrationTest.cs\", \"language\": \"csharp\" }\n  ]\n}\n```\n\n### How it works\n\n1. **File discovery** — recursive walk pruning common build\u002Fvendor dirs (`bin`,\n   `obj`, `node_modules`, `target`, `dist`, `build`, `vendor`, `__pycache__`,\n   `.venv`, `.git`, …) and generated files (`.d.ts`, `.g.cs`, `.Designer.cs`,\n   `_pb2.py`, `*.min.js`, `AssemblyInfo.cs`, …).\n2. **Language detection** — `detect_language_from_path` maps the extension to a\n   supported language; unknown extensions are skipped.\n3. **Test-vs-source classification** — per-language path heuristics:\n\n   | Language | Test rule |\n   |---|---|\n   | Python | path contains `tests\u002F`\u002F`test\u002F`; or filename starts with `test_` or ends `_test.py`; or `conftest.py`. |\n   | JS\u002FTS\u002FTSX | path contains `__tests__`, `tests`, `test`, `spec`, `e2e`; or filename contains `.test.`\u002F`.spec.`. |\n   | Go | filename ends `_test.go`. |\n   | Java | path contains `test`\u002F`tests`; or filename ends `Test.java`\u002F`Tests.java`. |\n   | Rust | path contains `tests\u002F`\u002F`benches\u002F`. |\n   | C# | path contains `tests\u002F`; or project segment ends `.Tests`\u002F`.Test`\u002F`.UnitTests`\u002F`.IntegrationTests`; or filename ends `Tests`\u002F`Test`. |\n   | Ruby | path contains `spec\u002F`\u002F`test\u002F`; or filename ends `_spec.rb`\u002F`_test.rb`. |\n\n4. **Per-file extraction** — `process(text, ProcessConfig(structure, imports,\n   symbols))` returns declared items, raw import statements, and a flat declared\n   -name list.\n5. **Pairing** — for each test file, union **import resolution** (per language,\n   e.g. Python `from pkg.mod import x` → `pkg\u002Fmod.py`; Java `import a.b.C;` →\n   `a\u002Fb\u002FC.java`; C# `using` is namespace-not-file, so a no-op) with **identifier\n   overlap** (word-like tokens, length ≥ 4, matched against declared names).\n6. **JSON emit** — `untested_sources` ordered by declaration count descending.\n\n## Limitations (be honest with the agent)\n\nBoth engines are static, parse-only heuristics that trade a little accuracy for\norders-of-magnitude lower cost than coverage. Known gaps:\n\n- **Reflection \u002F DI-resolved types** referenced only via a string name or\n  container resolution won't be detected — the type's short name never appears\n  in the test source.\n- **Extension methods** invoked as instance methods (C#): the declaring static\n  class is not named, so its file is not credited.\n- **`var`, target-typed `new()`, pattern matching** lose the type token; the\n  file-level union usually still catches it through other references.\n- **Short identifier names** (polyglot, \u003C 4 chars) are dropped to avoid noisy\n  pairings on names like `id`, `db`, `Tag`.\n- **Monorepo path aliases** (TS path mapping, Java module-info) are not\n  resolved; a suffix-match fallback may pick the wrong source if two files share\n  a trailing path segment.\n\nFor these cases, run actual coverage (`coverage-analysis`) on the unpaired\ncandidates the agent has already triaged.\n\nAlways label the final result as a static pairing heuristic, not evidence of\nline or branch coverage. Include that caveat even when every requested source\nfile has an obvious matching or missing test.\n\n## Outputs the agent should consume\n\n- `untested[*].source` \u002F `untested_sources[*].path` — pick the next source file\n  to test (highest declaration count first).\n- `*.suggested_test_path` — drop-in target for the new test file; the Roslyn\n  engine honors the test project that already `\u003CProjectReference>`s the source's\n  project, so `dotnet sln add` is not needed. The polyglot engine may suggest a\n  co-located test when no test root is discoverable; that is a valid fallback,\n  but prefer an established repository test directory when one exists.\n- `source_to_tests` (Roslyn) \u002F `--include-tested` `tested_sources` (polyglot) —\n  verify a newly written test file lands in the list for the intended source.\n- `orphan_tests` (polyglot) — tests that don't reference any same-language\n  source file; useful for triaging stale or integration-only tests.\n",{"data":35,"body":36},{"name":4,"description":6,"license":25},{"type":37,"children":38},"root",[39,47,54,60,73,93,99,104,232,244,250,288,294,318,324,383,389,396,433,439,533,538,544,770,776,1111,1117,1122,1149,1154,1252,1272,1277,1462,1467,2031,2037,2042,2130,2142,2147,2153,2236],{"type":40,"tag":41,"props":42,"children":43},"element","h1",{"id":4},[44],{"type":45,"value":46},"text","Find Untested Sources",{"type":40,"tag":48,"props":49,"children":51},"h2",{"id":50},"purpose",[52],{"type":45,"value":53},"Purpose",{"type":40,"tag":55,"props":56,"children":57},"p",{},[58],{"type":45,"value":59},"Coverage tools answer \"which lines were executed?\" — they require a green build\nand a passing test run, which is minutes-to-tens-of-minutes on a real repo. The\nquestion this skill answers is different and much cheaper:",{"type":40,"tag":61,"props":62,"children":63},"blockquote",{},[64],{"type":40,"tag":55,"props":65,"children":66},{},[67],{"type":40,"tag":68,"props":69,"children":70},"em",{},[71],{"type":45,"value":72},"Which source files have no test file referencing any of their declared\ntypes\u002Fsymbols?",{"type":40,"tag":55,"props":74,"children":75},{},[76,78,84,86,91],{"type":45,"value":77},"That's the question an agent asks ",{"type":40,"tag":79,"props":80,"children":81},"strong",{},[82],{"type":45,"value":83},"before",{"type":45,"value":85}," writing a new test — and it can be\nanswered statically in a few seconds by parsing source files, with ",{"type":40,"tag":79,"props":87,"children":88},{},[89],{"type":45,"value":90},"no build,\nno dependency resolution, and no compilation",{"type":45,"value":92},". The output is a deterministic\ntest-pairing map that lets the agent pick the next file to test without reading\nthe entire codebase first.",{"type":40,"tag":48,"props":94,"children":96},{"id":95},"two-engines-pick-one",[97],{"type":45,"value":98},"Two engines — pick one",{"type":40,"tag":55,"props":100,"children":101},{},[102],{"type":45,"value":103},"This skill ships two interchangeable analyzers with a compatible JSON contract:",{"type":40,"tag":105,"props":106,"children":107},"table",{},[108,132],{"type":40,"tag":109,"props":110,"children":111},"thead",{},[112],{"type":40,"tag":113,"props":114,"children":115},"tr",{},[116,122,127],{"type":40,"tag":117,"props":118,"children":119},"th",{},[120],{"type":45,"value":121},"Engine",{"type":40,"tag":117,"props":123,"children":124},{},[125],{"type":45,"value":126},"Script",{"type":40,"tag":117,"props":128,"children":129},{},[130],{"type":45,"value":131},"Use when",{"type":40,"tag":133,"props":134,"children":135},"tbody",{},[136,201],{"type":40,"tag":113,"props":137,"children":138},{},[139,148,158],{"type":40,"tag":140,"props":141,"children":142},"td",{},[143],{"type":40,"tag":79,"props":144,"children":145},{},[146],{"type":45,"value":147},"Roslyn (C#)",{"type":40,"tag":140,"props":149,"children":150},{},[151],{"type":40,"tag":152,"props":153,"children":155},"code",{"className":154},[],[156],{"type":45,"value":157},"scripts\u002FFind-UntestedSources.cs",{"type":40,"tag":140,"props":159,"children":160},{},[161,163,168,170,176,178,183,185,191,193,199],{"type":45,"value":162},"The repo is ",{"type":40,"tag":79,"props":164,"children":165},{},[166],{"type":45,"value":167},".NET-only",{"type":45,"value":169},". Parses every ",{"type":40,"tag":152,"props":171,"children":173},{"className":172},[],[174],{"type":45,"value":175},".cs",{"type":45,"value":177}," file with the Roslyn syntax API and does strict ",{"type":40,"tag":79,"props":179,"children":180},{},[181],{"type":45,"value":182},"namespace disambiguation",{"type":45,"value":184},", so it is materially more accurate on duplicated short names like ",{"type":40,"tag":152,"props":186,"children":188},{"className":187},[],[189],{"type":45,"value":190},"Settings",{"type":45,"value":192}," or ",{"type":40,"tag":152,"props":194,"children":196},{"className":195},[],[197],{"type":45,"value":198},"Context",{"type":45,"value":200},".",{"type":40,"tag":113,"props":202,"children":203},{},[204,212,221],{"type":40,"tag":140,"props":205,"children":206},{},[207],{"type":40,"tag":79,"props":208,"children":209},{},[210],{"type":45,"value":211},"tree-sitter (polyglot)",{"type":40,"tag":140,"props":213,"children":214},{},[215],{"type":40,"tag":152,"props":216,"children":218},{"className":217},[],[219],{"type":45,"value":220},"scripts\u002Ffind_untested_sources.py",{"type":40,"tag":140,"props":222,"children":223},{},[224,225,230],{"type":45,"value":162},{"type":40,"tag":79,"props":226,"children":227},{},[228],{"type":45,"value":229},"not exclusively C#",{"type":45,"value":231},", or you want one tool across Python, TypeScript\u002FJavaScript, Go, Java, Rust, Ruby, and C#.",{"type":40,"tag":55,"props":233,"children":234},{},[235,237,242],{"type":45,"value":236},"For a .NET-only repository, ",{"type":40,"tag":79,"props":238,"children":239},{},[240],{"type":45,"value":241},"prefer the Roslyn engine",{"type":45,"value":243}," — its namespace-aware\npairing beats the polyglot engine's identifier overlap.",{"type":40,"tag":48,"props":245,"children":247},{"id":246},"required-workflow",[248],{"type":45,"value":249},"Required workflow",{"type":40,"tag":251,"props":252,"children":253},"ol",{},[254,260,273,278,283],{"type":40,"tag":255,"props":256,"children":257},"li",{},[258],{"type":45,"value":259},"Use the narrowest repository or package root named by the caller. Do not scan\na parent workspace when the request identifies a subdirectory.",{"type":40,"tag":255,"props":261,"children":262},{},[263,265,271],{"type":45,"value":264},"Execute the appropriate analyzer once. Do not replace analyzer execution with\nmanual globbing, filename matching, or visual inspection.\nFor polyglot analysis, pass ",{"type":40,"tag":152,"props":266,"children":268},{"className":267},[],[269],{"type":45,"value":270},"--include-tested",{"type":45,"value":272}," when the answer must distinguish\npaired sources from unpaired sources.",{"type":40,"tag":255,"props":274,"children":275},{},[276],{"type":45,"value":277},"Base the result on the analyzer's JSON. Preserve its paired\u002Funpaired\nclassification and suggested relative path; do not guess a different path.",{"type":40,"tag":255,"props":279,"children":280},{},[281],{"type":45,"value":282},"When the caller named a subdirectory, prefix analyzer-relative paths with\nthat subdirectory so reported paths are workspace-relative.",{"type":40,"tag":255,"props":284,"children":285},{},[286],{"type":45,"value":287},"Report the requested result plus the static-pairing coverage caveat. Do not\nappend build, package-install, test-run, or coverage commands. When paired\nsources exist, name their covering test files so the unpaired classification\nis auditable.",{"type":40,"tag":48,"props":289,"children":291},{"id":290},"when-to-use",[292],{"type":45,"value":293},"When to Use",{"type":40,"tag":295,"props":296,"children":297},"ul",{},[298,303,308,313],{"type":40,"tag":255,"props":299,"children":300},{},[301],{"type":45,"value":302},"User asks \"where should I add tests?\", \"which files have no tests?\", \"find\nuntested code\", \"give me a test gap list\", \"what's the next file to test\".",{"type":40,"tag":255,"props":304,"children":305},{},[306],{"type":45,"value":307},"Before invoking a test-generation agent, to produce a prioritized worklist.",{"type":40,"tag":255,"props":309,"children":310},{},[311],{"type":45,"value":312},"After generating tests, to verify each new test file pairs to a source file.",{"type":40,"tag":255,"props":314,"children":315},{},[316],{"type":45,"value":317},"To enumerate \"weakly paired\" source files (only one referring test) for\nfollow-up depth checks.",{"type":40,"tag":48,"props":319,"children":321},{"id":320},"when-not-to-use",[322],{"type":45,"value":323},"When Not to Use",{"type":40,"tag":295,"props":325,"children":326},{},[327,344,359],{"type":40,"tag":255,"props":328,"children":329},{},[330,335,337,343],{"type":40,"tag":79,"props":331,"children":332},{},[333],{"type":45,"value":334},"Line\u002Fbranch coverage",{"type":45,"value":336}," — use ",{"type":40,"tag":152,"props":338,"children":340},{"className":339},[],[341],{"type":45,"value":342},"coverage-analysis",{"type":45,"value":200},{"type":40,"tag":255,"props":345,"children":346},{},[347,352,353,358],{"type":40,"tag":79,"props":348,"children":349},{},[350],{"type":45,"value":351},"CRAP-score \u002F risk hotspots",{"type":45,"value":336},{"type":40,"tag":152,"props":354,"children":356},{"className":355},[],[357],{"type":45,"value":342},{"type":45,"value":200},{"type":40,"tag":255,"props":360,"children":361},{},[362,367,368,374,376,382],{"type":40,"tag":79,"props":363,"children":364},{},[365],{"type":45,"value":366},"Are existing tests strong?",{"type":45,"value":336},{"type":40,"tag":152,"props":369,"children":371},{"className":370},[],[372],{"type":45,"value":373},"test-gap-analysis",{"type":45,"value":375}," (mutation reasoning)\nor ",{"type":40,"tag":152,"props":377,"children":379},{"className":378},[],[380],{"type":45,"value":381},"assertion-quality",{"type":45,"value":200},{"type":40,"tag":48,"props":384,"children":386},{"id":385},"roslyn-engine-c",[387],{"type":45,"value":388},"Roslyn engine (C#)",{"type":40,"tag":390,"props":391,"children":393},"h3",{"id":392},"prerequisites",[394],{"type":45,"value":395},"Prerequisites",{"type":40,"tag":295,"props":397,"children":398},{},[399,420],{"type":40,"tag":255,"props":400,"children":401},{},[402,404,410,412,418],{"type":45,"value":403},".NET SDK that supports file-based apps (",{"type":40,"tag":152,"props":405,"children":407},{"className":406},[],[408],{"type":45,"value":409},"dotnet run script.cs",{"type":45,"value":411},"). Pinned in the\nrepo's ",{"type":40,"tag":152,"props":413,"children":415},{"className":414},[],[416],{"type":45,"value":417},"global.json",{"type":45,"value":419}," (SDK 11 preview or later).",{"type":40,"tag":255,"props":421,"children":422},{},[423,425,431],{"type":45,"value":424},"No internet access required beyond the initial NuGet restore of\n",{"type":40,"tag":152,"props":426,"children":428},{"className":427},[],[429],{"type":45,"value":430},"Microsoft.CodeAnalysis.CSharp",{"type":45,"value":432}," on first run.",{"type":40,"tag":390,"props":434,"children":436},{"id":435},"usage",[437],{"type":45,"value":438},"Usage",{"type":40,"tag":440,"props":441,"children":446},"pre",{"className":442,"code":443,"language":444,"meta":445,"style":445},"language-powershell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# From the skill folder\ndotnet run scripts\u002FFind-UntestedSources.cs -- \u003Crepo-root> [--top N]\n\n# Save the report\ndotnet run scripts\u002FFind-UntestedSources.cs -- \u003Crepo-root> > pairing.json\n\n# Iterate the untested list, highest-API-surface first\n$report = Get-Content pairing.json | ConvertFrom-Json\n$report.untested | Select-Object -First 10 source, decl_count, suggested_test_path\n","powershell","",[447],{"type":40,"tag":152,"props":448,"children":449},{"__ignoreMap":445},[450,461,470,480,489,498,506,515,524],{"type":40,"tag":451,"props":452,"children":455},"span",{"class":453,"line":454},"line",1,[456],{"type":40,"tag":451,"props":457,"children":458},{},[459],{"type":45,"value":460},"# From the skill folder\n",{"type":40,"tag":451,"props":462,"children":464},{"class":453,"line":463},2,[465],{"type":40,"tag":451,"props":466,"children":467},{},[468],{"type":45,"value":469},"dotnet run scripts\u002FFind-UntestedSources.cs -- \u003Crepo-root> [--top N]\n",{"type":40,"tag":451,"props":471,"children":473},{"class":453,"line":472},3,[474],{"type":40,"tag":451,"props":475,"children":477},{"emptyLinePlaceholder":476},true,[478],{"type":45,"value":479},"\n",{"type":40,"tag":451,"props":481,"children":483},{"class":453,"line":482},4,[484],{"type":40,"tag":451,"props":485,"children":486},{},[487],{"type":45,"value":488},"# Save the report\n",{"type":40,"tag":451,"props":490,"children":492},{"class":453,"line":491},5,[493],{"type":40,"tag":451,"props":494,"children":495},{},[496],{"type":45,"value":497},"dotnet run scripts\u002FFind-UntestedSources.cs -- \u003Crepo-root> > pairing.json\n",{"type":40,"tag":451,"props":499,"children":501},{"class":453,"line":500},6,[502],{"type":40,"tag":451,"props":503,"children":504},{"emptyLinePlaceholder":476},[505],{"type":45,"value":479},{"type":40,"tag":451,"props":507,"children":509},{"class":453,"line":508},7,[510],{"type":40,"tag":451,"props":511,"children":512},{},[513],{"type":45,"value":514},"# Iterate the untested list, highest-API-surface first\n",{"type":40,"tag":451,"props":516,"children":518},{"class":453,"line":517},8,[519],{"type":40,"tag":451,"props":520,"children":521},{},[522],{"type":45,"value":523},"$report = Get-Content pairing.json | ConvertFrom-Json\n",{"type":40,"tag":451,"props":525,"children":527},{"class":453,"line":526},9,[528],{"type":40,"tag":451,"props":529,"children":530},{},[531],{"type":45,"value":532},"$report.untested | Select-Object -First 10 source, decl_count, suggested_test_path\n",{"type":40,"tag":55,"props":534,"children":535},{},[536],{"type":45,"value":537},"Diagnostics go to stderr; JSON goes to stdout.",{"type":40,"tag":390,"props":539,"children":541},{"id":540},"output-schema",[542],{"type":45,"value":543},"Output schema",{"type":40,"tag":440,"props":545,"children":549},{"className":546,"code":547,"language":548,"meta":445,"style":445},"language-jsonc shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"repo\": \"\u003Cabsolute path>\",\n  \"elapsed_ms\": 8883,\n  \"counts\": {\n    \"source_files\": 3036,\n    \"test_files\": 867,\n    \"untested_files\": 1852,\n    \"paired_files\": 1184\n  },\n  \"untested\": [\n    {\n      \"source\": \"src\u002FFoo\u002FBar.cs\",\n      \"decl_count\": 8,            \u002F\u002F # of type declarations in the file\n      \"suggested_test_path\":      \u002F\u002F mirror of source under a discovered test project\n        \"tests\u002FFoo.Tests\u002FBar\u002FBarTests.cs\"\n    }\n  ],\n  \"source_to_tests\": {\n    \"src\u002FFoo\u002FBaz.cs\": [\n      \"tests\u002FFoo.Tests\u002FBazTests.cs\",\n      \"tests\u002FFoo.IntegrationTests\u002FScenarios\u002FBazScenarios.cs\"\n    ]\n  }\n}\n","jsonc",[550],{"type":40,"tag":152,"props":551,"children":552},{"__ignoreMap":445},[553,561,569,577,585,593,601,609,617,625,634,643,652,666,680,689,698,707,716,725,734,743,752,761],{"type":40,"tag":451,"props":554,"children":555},{"class":453,"line":454},[556],{"type":40,"tag":451,"props":557,"children":558},{},[559],{"type":45,"value":560},"{\n",{"type":40,"tag":451,"props":562,"children":563},{"class":453,"line":463},[564],{"type":40,"tag":451,"props":565,"children":566},{},[567],{"type":45,"value":568},"  \"repo\": \"\u003Cabsolute path>\",\n",{"type":40,"tag":451,"props":570,"children":571},{"class":453,"line":472},[572],{"type":40,"tag":451,"props":573,"children":574},{},[575],{"type":45,"value":576},"  \"elapsed_ms\": 8883,\n",{"type":40,"tag":451,"props":578,"children":579},{"class":453,"line":482},[580],{"type":40,"tag":451,"props":581,"children":582},{},[583],{"type":45,"value":584},"  \"counts\": {\n",{"type":40,"tag":451,"props":586,"children":587},{"class":453,"line":491},[588],{"type":40,"tag":451,"props":589,"children":590},{},[591],{"type":45,"value":592},"    \"source_files\": 3036,\n",{"type":40,"tag":451,"props":594,"children":595},{"class":453,"line":500},[596],{"type":40,"tag":451,"props":597,"children":598},{},[599],{"type":45,"value":600},"    \"test_files\": 867,\n",{"type":40,"tag":451,"props":602,"children":603},{"class":453,"line":508},[604],{"type":40,"tag":451,"props":605,"children":606},{},[607],{"type":45,"value":608},"    \"untested_files\": 1852,\n",{"type":40,"tag":451,"props":610,"children":611},{"class":453,"line":517},[612],{"type":40,"tag":451,"props":613,"children":614},{},[615],{"type":45,"value":616},"    \"paired_files\": 1184\n",{"type":40,"tag":451,"props":618,"children":619},{"class":453,"line":526},[620],{"type":40,"tag":451,"props":621,"children":622},{},[623],{"type":45,"value":624},"  },\n",{"type":40,"tag":451,"props":626,"children":628},{"class":453,"line":627},10,[629],{"type":40,"tag":451,"props":630,"children":631},{},[632],{"type":45,"value":633},"  \"untested\": [\n",{"type":40,"tag":451,"props":635,"children":637},{"class":453,"line":636},11,[638],{"type":40,"tag":451,"props":639,"children":640},{},[641],{"type":45,"value":642},"    {\n",{"type":40,"tag":451,"props":644,"children":646},{"class":453,"line":645},12,[647],{"type":40,"tag":451,"props":648,"children":649},{},[650],{"type":45,"value":651},"      \"source\": \"src\u002FFoo\u002FBar.cs\",\n",{"type":40,"tag":451,"props":653,"children":655},{"class":453,"line":654},13,[656,661],{"type":40,"tag":451,"props":657,"children":658},{},[659],{"type":45,"value":660},"      \"decl_count\": 8,",{"type":40,"tag":451,"props":662,"children":663},{},[664],{"type":45,"value":665},"            \u002F\u002F # of type declarations in the file\n",{"type":40,"tag":451,"props":667,"children":669},{"class":453,"line":668},14,[670,675],{"type":40,"tag":451,"props":671,"children":672},{},[673],{"type":45,"value":674},"      \"suggested_test_path\":",{"type":40,"tag":451,"props":676,"children":677},{},[678],{"type":45,"value":679},"      \u002F\u002F mirror of source under a discovered test project\n",{"type":40,"tag":451,"props":681,"children":683},{"class":453,"line":682},15,[684],{"type":40,"tag":451,"props":685,"children":686},{},[687],{"type":45,"value":688},"        \"tests\u002FFoo.Tests\u002FBar\u002FBarTests.cs\"\n",{"type":40,"tag":451,"props":690,"children":692},{"class":453,"line":691},16,[693],{"type":40,"tag":451,"props":694,"children":695},{},[696],{"type":45,"value":697},"    }\n",{"type":40,"tag":451,"props":699,"children":701},{"class":453,"line":700},17,[702],{"type":40,"tag":451,"props":703,"children":704},{},[705],{"type":45,"value":706},"  ],\n",{"type":40,"tag":451,"props":708,"children":710},{"class":453,"line":709},18,[711],{"type":40,"tag":451,"props":712,"children":713},{},[714],{"type":45,"value":715},"  \"source_to_tests\": {\n",{"type":40,"tag":451,"props":717,"children":719},{"class":453,"line":718},19,[720],{"type":40,"tag":451,"props":721,"children":722},{},[723],{"type":45,"value":724},"    \"src\u002FFoo\u002FBaz.cs\": [\n",{"type":40,"tag":451,"props":726,"children":728},{"class":453,"line":727},20,[729],{"type":40,"tag":451,"props":730,"children":731},{},[732],{"type":45,"value":733},"      \"tests\u002FFoo.Tests\u002FBazTests.cs\",\n",{"type":40,"tag":451,"props":735,"children":737},{"class":453,"line":736},21,[738],{"type":40,"tag":451,"props":739,"children":740},{},[741],{"type":45,"value":742},"      \"tests\u002FFoo.IntegrationTests\u002FScenarios\u002FBazScenarios.cs\"\n",{"type":40,"tag":451,"props":744,"children":746},{"class":453,"line":745},22,[747],{"type":40,"tag":451,"props":748,"children":749},{},[750],{"type":45,"value":751},"    ]\n",{"type":40,"tag":451,"props":753,"children":755},{"class":453,"line":754},23,[756],{"type":40,"tag":451,"props":757,"children":758},{},[759],{"type":45,"value":760},"  }\n",{"type":40,"tag":451,"props":762,"children":764},{"class":453,"line":763},24,[765],{"type":40,"tag":451,"props":766,"children":767},{},[768],{"type":45,"value":769},"}\n",{"type":40,"tag":390,"props":771,"children":773},{"id":772},"how-it-works",[774],{"type":45,"value":775},"How it works",{"type":40,"tag":251,"props":777,"children":778},{},[779,856,981,1022,1075,1101],{"type":40,"tag":255,"props":780,"children":781},{},[782,787,789,795,797,803,804,810,812,818,819,825,826,832,834,840,841,847,848,854],{"type":40,"tag":79,"props":783,"children":784},{},[785],{"type":45,"value":786},"File discovery",{"type":45,"value":788}," — recursive walk pruning ",{"type":40,"tag":152,"props":790,"children":792},{"className":791},[],[793],{"type":45,"value":794},"bin\u002F",{"type":45,"value":796},", ",{"type":40,"tag":152,"props":798,"children":800},{"className":799},[],[801],{"type":45,"value":802},"obj\u002F",{"type":45,"value":796},{"type":40,"tag":152,"props":805,"children":807},{"className":806},[],[808],{"type":45,"value":809},"node_modules\u002F",{"type":45,"value":811},",\n",{"type":40,"tag":152,"props":813,"children":815},{"className":814},[],[816],{"type":45,"value":817},".git\u002F",{"type":45,"value":796},{"type":40,"tag":152,"props":820,"children":822},{"className":821},[],[823],{"type":45,"value":824},".vs\u002F",{"type":45,"value":796},{"type":40,"tag":152,"props":827,"children":829},{"className":828},[],[830],{"type":45,"value":831},"packages\u002F",{"type":45,"value":833},", and any dotted subdir. Skips generated files\n(",{"type":40,"tag":152,"props":835,"children":837},{"className":836},[],[838],{"type":45,"value":839},".g.cs",{"type":45,"value":796},{"type":40,"tag":152,"props":842,"children":844},{"className":843},[],[845],{"type":45,"value":846},".Designer.cs",{"type":45,"value":796},{"type":40,"tag":152,"props":849,"children":851},{"className":850},[],[852],{"type":45,"value":853},".AssemblyInfo.cs",{"type":45,"value":855},").",{"type":40,"tag":255,"props":857,"children":858},{},[859,864,866,872,874,880,881,887,888,894,895,901,902,908,909,915,916,922,923,929,931,937,938,944,945,951,952,958,959,965,966,972,974,980],{"type":40,"tag":79,"props":860,"children":861},{},[862],{"type":45,"value":863},"Test vs source classification",{"type":45,"value":865}," — walks up to the nearest ",{"type":40,"tag":152,"props":867,"children":869},{"className":868},[],[870],{"type":45,"value":871},".csproj",{"type":45,"value":873}," and\nmarks it a test project if the project name ends in ",{"type":40,"tag":152,"props":875,"children":877},{"className":876},[],[878],{"type":45,"value":879},".Tests",{"type":45,"value":796},{"type":40,"tag":152,"props":882,"children":884},{"className":883},[],[885],{"type":45,"value":886},".Test",{"type":45,"value":811},{"type":40,"tag":152,"props":889,"children":891},{"className":890},[],[892],{"type":45,"value":893},".UnitTests",{"type":45,"value":796},{"type":40,"tag":152,"props":896,"children":898},{"className":897},[],[899],{"type":45,"value":900},".IntegrationTests",{"type":45,"value":796},{"type":40,"tag":152,"props":903,"children":905},{"className":904},[],[906],{"type":45,"value":907},".E2E",{"type":45,"value":796},{"type":40,"tag":152,"props":910,"children":912},{"className":911},[],[913],{"type":45,"value":914},".EndToEnd",{"type":45,"value":796},{"type":40,"tag":152,"props":917,"children":919},{"className":918},[],[920],{"type":45,"value":921},".Spec",{"type":45,"value":796},{"type":40,"tag":152,"props":924,"children":926},{"className":925},[],[927],{"type":45,"value":928},".Specs",{"type":45,"value":930},", or\nthe content references ",{"type":40,"tag":152,"props":932,"children":934},{"className":933},[],[935],{"type":45,"value":936},"Microsoft.NET.Test.Sdk",{"type":45,"value":796},{"type":40,"tag":152,"props":939,"children":941},{"className":940},[],[942],{"type":45,"value":943},"MSTest.Sdk",{"type":45,"value":811},{"type":40,"tag":152,"props":946,"children":948},{"className":947},[],[949],{"type":45,"value":950},"Microsoft.Testing.Platform",{"type":45,"value":796},{"type":40,"tag":152,"props":953,"children":955},{"className":954},[],[956],{"type":45,"value":957},"xunit",{"type":45,"value":796},{"type":40,"tag":152,"props":960,"children":962},{"className":961},[],[963],{"type":45,"value":964},"NUnit",{"type":45,"value":796},{"type":40,"tag":152,"props":967,"children":969},{"className":968},[],[970],{"type":45,"value":971},"TUnit",{"type":45,"value":973},", or\n",{"type":40,"tag":152,"props":975,"children":977},{"className":976},[],[978],{"type":45,"value":979},"\u003CIsTestProject>true\u003C\u002FIsTestProject>",{"type":45,"value":200},{"type":40,"tag":255,"props":982,"children":983},{},[984,989,991,997,999,1005,1007,1013,1015,1021],{"type":40,"tag":79,"props":985,"children":986},{},[987],{"type":45,"value":988},"Source index (parallel)",{"type":45,"value":990}," — parse each source file with\n",{"type":40,"tag":152,"props":992,"children":994},{"className":993},[],[995],{"type":45,"value":996},"CSharpSyntaxTree.ParseText",{"type":45,"value":998}," (syntax only, no compilation); record every\n",{"type":40,"tag":152,"props":1000,"children":1002},{"className":1001},[],[1003],{"type":45,"value":1004},"BaseTypeDeclarationSyntax",{"type":45,"value":1006}," \u002F ",{"type":40,"tag":152,"props":1008,"children":1010},{"className":1009},[],[1011],{"type":45,"value":1012},"DelegateDeclarationSyntax",{"type":45,"value":1014}," as\n",{"type":40,"tag":152,"props":1016,"children":1018},{"className":1017},[],[1019],{"type":45,"value":1020},"(ShortName, EnclosingNamespace, FilePath)",{"type":45,"value":200},{"type":40,"tag":255,"props":1023,"children":1024},{},[1025,1030,1032,1038,1040,1046,1048,1053,1055,1060,1062,1067,1068,1073],{"type":40,"tag":79,"props":1026,"children":1027},{},[1028],{"type":45,"value":1029},"Test scan (parallel)",{"type":45,"value":1031}," — parse each test file, collect ",{"type":40,"tag":152,"props":1033,"children":1035},{"className":1034},[],[1036],{"type":45,"value":1037},"using",{"type":45,"value":1039}," directives +\nenclosing namespace, walk every ",{"type":40,"tag":152,"props":1041,"children":1043},{"className":1042},[],[1044],{"type":45,"value":1045},"IdentifierToken",{"type":45,"value":1047},", look it up in the\nshort-name index, and ",{"type":40,"tag":79,"props":1049,"children":1050},{},[1051],{"type":45,"value":1052},"disambiguate strictly",{"type":45,"value":1054},": an identifier is attributed\nonly if the declaration's namespace matches one of the test file's ",{"type":40,"tag":152,"props":1056,"children":1058},{"className":1057},[],[1059],{"type":45,"value":1037},{"type":45,"value":1061},"\ndirectives, the enclosing namespace, or a prefix of them. This avoids noise\nwhere common names like ",{"type":40,"tag":152,"props":1063,"children":1065},{"className":1064},[],[1066],{"type":45,"value":190},{"type":45,"value":192},{"type":40,"tag":152,"props":1069,"children":1071},{"className":1070},[],[1072],{"type":45,"value":198},{"type":45,"value":1074}," match every project.",{"type":40,"tag":255,"props":1076,"children":1077},{},[1078,1083,1085,1091,1093,1099],{"type":40,"tag":79,"props":1079,"children":1080},{},[1081],{"type":45,"value":1082},"Pairing & suggestion",{"type":45,"value":1084}," — invert into ",{"type":40,"tag":152,"props":1086,"children":1088},{"className":1087},[],[1089],{"type":45,"value":1090},"source → [tests]",{"type":45,"value":1092},". Build a\nproduction-to-test project map from ",{"type":40,"tag":152,"props":1094,"children":1096},{"className":1095},[],[1097],{"type":45,"value":1098},"\u003CProjectReference>",{"type":45,"value":1100}," entries; for each\nuntested source, mirror its in-project relative path under the referencing\ntest project to suggest a path.",{"type":40,"tag":255,"props":1102,"children":1103},{},[1104,1109],{"type":40,"tag":79,"props":1105,"children":1106},{},[1107],{"type":45,"value":1108},"JSON emit",{"type":45,"value":1110}," — ordered by declaration count desc, then alphabetical.",{"type":40,"tag":48,"props":1112,"children":1114},{"id":1113},"polyglot-engine-tree-sitter",[1115],{"type":45,"value":1116},"Polyglot engine (tree-sitter)",{"type":40,"tag":390,"props":1118,"children":1120},{"id":1119},"prerequisites-1",[1121],{"type":45,"value":395},{"type":40,"tag":295,"props":1123,"children":1124},{},[1125,1130],{"type":40,"tag":255,"props":1126,"children":1127},{},[1128],{"type":45,"value":1129},"Python 3.10+.",{"type":40,"tag":255,"props":1131,"children":1132},{},[1133,1139,1141,1147],{"type":40,"tag":152,"props":1134,"children":1136},{"className":1135},[],[1137],{"type":45,"value":1138},"pip install tree-sitter-language-pack",{"type":45,"value":1140}," (single self-contained wheel that\nbundles parsers for 300+ languages and the high-level ",{"type":40,"tag":152,"props":1142,"children":1144},{"className":1143},[],[1145],{"type":45,"value":1146},"process()",{"type":45,"value":1148}," API). No\nnative build, no per-language grammar install.",{"type":40,"tag":390,"props":1150,"children":1152},{"id":1151},"usage-1",[1153],{"type":45,"value":438},{"type":40,"tag":440,"props":1155,"children":1157},{"className":442,"code":1156,"language":444,"meta":445,"style":445},"# From the skill folder\npython scripts\u002Ffind_untested_sources.py \u003Crepo-root>\n\n# Restrict to a language (repeatable)\npython scripts\u002Ffind_untested_sources.py \u003Crepo-root> --lang python --lang typescript\n\n# Truncate the report (top 20 by declared API surface)\npython scripts\u002Ffind_untested_sources.py \u003Crepo-root> --limit-untested 20 > pairing.json\n\n# Iterate, highest-API-surface first\n$report = Get-Content pairing.json | ConvertFrom-Json\n$report.untested_sources | Select-Object -First 10 path, declaration_count, suggested_test_path\n",[1158],{"type":40,"tag":152,"props":1159,"children":1160},{"__ignoreMap":445},[1161,1168,1176,1183,1191,1199,1206,1214,1222,1229,1237,1244],{"type":40,"tag":451,"props":1162,"children":1163},{"class":453,"line":454},[1164],{"type":40,"tag":451,"props":1165,"children":1166},{},[1167],{"type":45,"value":460},{"type":40,"tag":451,"props":1169,"children":1170},{"class":453,"line":463},[1171],{"type":40,"tag":451,"props":1172,"children":1173},{},[1174],{"type":45,"value":1175},"python scripts\u002Ffind_untested_sources.py \u003Crepo-root>\n",{"type":40,"tag":451,"props":1177,"children":1178},{"class":453,"line":472},[1179],{"type":40,"tag":451,"props":1180,"children":1181},{"emptyLinePlaceholder":476},[1182],{"type":45,"value":479},{"type":40,"tag":451,"props":1184,"children":1185},{"class":453,"line":482},[1186],{"type":40,"tag":451,"props":1187,"children":1188},{},[1189],{"type":45,"value":1190},"# Restrict to a language (repeatable)\n",{"type":40,"tag":451,"props":1192,"children":1193},{"class":453,"line":491},[1194],{"type":40,"tag":451,"props":1195,"children":1196},{},[1197],{"type":45,"value":1198},"python scripts\u002Ffind_untested_sources.py \u003Crepo-root> --lang python --lang typescript\n",{"type":40,"tag":451,"props":1200,"children":1201},{"class":453,"line":500},[1202],{"type":40,"tag":451,"props":1203,"children":1204},{"emptyLinePlaceholder":476},[1205],{"type":45,"value":479},{"type":40,"tag":451,"props":1207,"children":1208},{"class":453,"line":508},[1209],{"type":40,"tag":451,"props":1210,"children":1211},{},[1212],{"type":45,"value":1213},"# Truncate the report (top 20 by declared API surface)\n",{"type":40,"tag":451,"props":1215,"children":1216},{"class":453,"line":517},[1217],{"type":40,"tag":451,"props":1218,"children":1219},{},[1220],{"type":45,"value":1221},"python scripts\u002Ffind_untested_sources.py \u003Crepo-root> --limit-untested 20 > pairing.json\n",{"type":40,"tag":451,"props":1223,"children":1224},{"class":453,"line":526},[1225],{"type":40,"tag":451,"props":1226,"children":1227},{"emptyLinePlaceholder":476},[1228],{"type":45,"value":479},{"type":40,"tag":451,"props":1230,"children":1231},{"class":453,"line":627},[1232],{"type":40,"tag":451,"props":1233,"children":1234},{},[1235],{"type":45,"value":1236},"# Iterate, highest-API-surface first\n",{"type":40,"tag":451,"props":1238,"children":1239},{"class":453,"line":636},[1240],{"type":40,"tag":451,"props":1241,"children":1242},{},[1243],{"type":45,"value":523},{"type":40,"tag":451,"props":1245,"children":1246},{"class":453,"line":645},[1247],{"type":40,"tag":451,"props":1248,"children":1249},{},[1250],{"type":45,"value":1251},"$report.untested_sources | Select-Object -First 10 path, declaration_count, suggested_test_path\n",{"type":40,"tag":55,"props":1253,"children":1254},{},[1255,1257,1262,1264,1270],{"type":45,"value":1256},"Pass ",{"type":40,"tag":152,"props":1258,"children":1260},{"className":1259},[],[1261],{"type":45,"value":270},{"type":45,"value":1263}," to additionally emit ",{"type":40,"tag":152,"props":1265,"children":1267},{"className":1266},[],[1268],{"type":45,"value":1269},"tested_sources",{"type":45,"value":1271}," (omitted by\ndefault to keep the payload small for LLM consumption). Diagnostics go to\nstderr; JSON goes to stdout.",{"type":40,"tag":390,"props":1273,"children":1275},{"id":1274},"output-schema-1",[1276],{"type":45,"value":543},{"type":40,"tag":440,"props":1278,"children":1280},{"className":546,"code":1279,"language":548,"meta":445,"style":445},"{\n  \"repo_root\": \"\u003Cabsolute path>\",\n  \"summary\": {\n    \"source_files\": 3138,\n    \"test_files\": 761,\n    \"tested_source_files\": 1419,\n    \"untested_source_files\": 1719,\n    \"orphan_test_files\": 15,\n    \"languages\": [\"csharp\"]\n  },\n  \"untested_sources\": [\n    {\n      \"path\": \"src\u002FFoo\u002FBar.cs\",\n      \"language\": \"csharp\",\n      \"declaration_count\": 8,\n      \"declarations\": [\"Bar\", \"BarOptions\", \"IBar\", \"...\"],\n      \"suggested_test_path\": \"src\u002FFoo\u002FBarTests.cs\"\n    }\n  ],\n  \"orphan_tests\": [\n    { \"path\": \"tests\u002FSomeIntegrationTest.cs\", \"language\": \"csharp\" }\n  ]\n}\n",[1281],{"type":40,"tag":152,"props":1282,"children":1283},{"__ignoreMap":445},[1284,1291,1299,1307,1315,1323,1331,1339,1347,1355,1362,1370,1377,1385,1393,1401,1409,1417,1424,1431,1439,1447,1455],{"type":40,"tag":451,"props":1285,"children":1286},{"class":453,"line":454},[1287],{"type":40,"tag":451,"props":1288,"children":1289},{},[1290],{"type":45,"value":560},{"type":40,"tag":451,"props":1292,"children":1293},{"class":453,"line":463},[1294],{"type":40,"tag":451,"props":1295,"children":1296},{},[1297],{"type":45,"value":1298},"  \"repo_root\": \"\u003Cabsolute path>\",\n",{"type":40,"tag":451,"props":1300,"children":1301},{"class":453,"line":472},[1302],{"type":40,"tag":451,"props":1303,"children":1304},{},[1305],{"type":45,"value":1306},"  \"summary\": {\n",{"type":40,"tag":451,"props":1308,"children":1309},{"class":453,"line":482},[1310],{"type":40,"tag":451,"props":1311,"children":1312},{},[1313],{"type":45,"value":1314},"    \"source_files\": 3138,\n",{"type":40,"tag":451,"props":1316,"children":1317},{"class":453,"line":491},[1318],{"type":40,"tag":451,"props":1319,"children":1320},{},[1321],{"type":45,"value":1322},"    \"test_files\": 761,\n",{"type":40,"tag":451,"props":1324,"children":1325},{"class":453,"line":500},[1326],{"type":40,"tag":451,"props":1327,"children":1328},{},[1329],{"type":45,"value":1330},"    \"tested_source_files\": 1419,\n",{"type":40,"tag":451,"props":1332,"children":1333},{"class":453,"line":508},[1334],{"type":40,"tag":451,"props":1335,"children":1336},{},[1337],{"type":45,"value":1338},"    \"untested_source_files\": 1719,\n",{"type":40,"tag":451,"props":1340,"children":1341},{"class":453,"line":517},[1342],{"type":40,"tag":451,"props":1343,"children":1344},{},[1345],{"type":45,"value":1346},"    \"orphan_test_files\": 15,\n",{"type":40,"tag":451,"props":1348,"children":1349},{"class":453,"line":526},[1350],{"type":40,"tag":451,"props":1351,"children":1352},{},[1353],{"type":45,"value":1354},"    \"languages\": [\"csharp\"]\n",{"type":40,"tag":451,"props":1356,"children":1357},{"class":453,"line":627},[1358],{"type":40,"tag":451,"props":1359,"children":1360},{},[1361],{"type":45,"value":624},{"type":40,"tag":451,"props":1363,"children":1364},{"class":453,"line":636},[1365],{"type":40,"tag":451,"props":1366,"children":1367},{},[1368],{"type":45,"value":1369},"  \"untested_sources\": [\n",{"type":40,"tag":451,"props":1371,"children":1372},{"class":453,"line":645},[1373],{"type":40,"tag":451,"props":1374,"children":1375},{},[1376],{"type":45,"value":642},{"type":40,"tag":451,"props":1378,"children":1379},{"class":453,"line":654},[1380],{"type":40,"tag":451,"props":1381,"children":1382},{},[1383],{"type":45,"value":1384},"      \"path\": \"src\u002FFoo\u002FBar.cs\",\n",{"type":40,"tag":451,"props":1386,"children":1387},{"class":453,"line":668},[1388],{"type":40,"tag":451,"props":1389,"children":1390},{},[1391],{"type":45,"value":1392},"      \"language\": \"csharp\",\n",{"type":40,"tag":451,"props":1394,"children":1395},{"class":453,"line":682},[1396],{"type":40,"tag":451,"props":1397,"children":1398},{},[1399],{"type":45,"value":1400},"      \"declaration_count\": 8,\n",{"type":40,"tag":451,"props":1402,"children":1403},{"class":453,"line":691},[1404],{"type":40,"tag":451,"props":1405,"children":1406},{},[1407],{"type":45,"value":1408},"      \"declarations\": [\"Bar\", \"BarOptions\", \"IBar\", \"...\"],\n",{"type":40,"tag":451,"props":1410,"children":1411},{"class":453,"line":700},[1412],{"type":40,"tag":451,"props":1413,"children":1414},{},[1415],{"type":45,"value":1416},"      \"suggested_test_path\": \"src\u002FFoo\u002FBarTests.cs\"\n",{"type":40,"tag":451,"props":1418,"children":1419},{"class":453,"line":709},[1420],{"type":40,"tag":451,"props":1421,"children":1422},{},[1423],{"type":45,"value":697},{"type":40,"tag":451,"props":1425,"children":1426},{"class":453,"line":718},[1427],{"type":40,"tag":451,"props":1428,"children":1429},{},[1430],{"type":45,"value":706},{"type":40,"tag":451,"props":1432,"children":1433},{"class":453,"line":727},[1434],{"type":40,"tag":451,"props":1435,"children":1436},{},[1437],{"type":45,"value":1438},"  \"orphan_tests\": [\n",{"type":40,"tag":451,"props":1440,"children":1441},{"class":453,"line":736},[1442],{"type":40,"tag":451,"props":1443,"children":1444},{},[1445],{"type":45,"value":1446},"    { \"path\": \"tests\u002FSomeIntegrationTest.cs\", \"language\": \"csharp\" }\n",{"type":40,"tag":451,"props":1448,"children":1449},{"class":453,"line":745},[1450],{"type":40,"tag":451,"props":1451,"children":1452},{},[1453],{"type":45,"value":1454},"  ]\n",{"type":40,"tag":451,"props":1456,"children":1457},{"class":453,"line":754},[1458],{"type":40,"tag":451,"props":1459,"children":1460},{},[1461],{"type":45,"value":769},{"type":40,"tag":390,"props":1463,"children":1465},{"id":1464},"how-it-works-1",[1466],{"type":45,"value":775},{"type":40,"tag":251,"props":1468,"children":1469},{},[1470,1591,1609,1935,1952,2015],{"type":40,"tag":255,"props":1471,"children":1472},{},[1473,1477,1479,1485,1486,1492,1493,1499,1500,1506,1507,1513,1514,1520,1521,1527,1528,1534,1535,1541,1542,1548,1550,1556,1557,1562,1563,1568,1569,1575,1576,1582,1583,1589],{"type":40,"tag":79,"props":1474,"children":1475},{},[1476],{"type":45,"value":786},{"type":45,"value":1478}," — recursive walk pruning common build\u002Fvendor dirs (",{"type":40,"tag":152,"props":1480,"children":1482},{"className":1481},[],[1483],{"type":45,"value":1484},"bin",{"type":45,"value":811},{"type":40,"tag":152,"props":1487,"children":1489},{"className":1488},[],[1490],{"type":45,"value":1491},"obj",{"type":45,"value":796},{"type":40,"tag":152,"props":1494,"children":1496},{"className":1495},[],[1497],{"type":45,"value":1498},"node_modules",{"type":45,"value":796},{"type":40,"tag":152,"props":1501,"children":1503},{"className":1502},[],[1504],{"type":45,"value":1505},"target",{"type":45,"value":796},{"type":40,"tag":152,"props":1508,"children":1510},{"className":1509},[],[1511],{"type":45,"value":1512},"dist",{"type":45,"value":796},{"type":40,"tag":152,"props":1515,"children":1517},{"className":1516},[],[1518],{"type":45,"value":1519},"build",{"type":45,"value":796},{"type":40,"tag":152,"props":1522,"children":1524},{"className":1523},[],[1525],{"type":45,"value":1526},"vendor",{"type":45,"value":796},{"type":40,"tag":152,"props":1529,"children":1531},{"className":1530},[],[1532],{"type":45,"value":1533},"__pycache__",{"type":45,"value":811},{"type":40,"tag":152,"props":1536,"children":1538},{"className":1537},[],[1539],{"type":45,"value":1540},".venv",{"type":45,"value":796},{"type":40,"tag":152,"props":1543,"children":1545},{"className":1544},[],[1546],{"type":45,"value":1547},".git",{"type":45,"value":1549},", …) and generated files (",{"type":40,"tag":152,"props":1551,"children":1553},{"className":1552},[],[1554],{"type":45,"value":1555},".d.ts",{"type":45,"value":796},{"type":40,"tag":152,"props":1558,"children":1560},{"className":1559},[],[1561],{"type":45,"value":839},{"type":45,"value":796},{"type":40,"tag":152,"props":1564,"children":1566},{"className":1565},[],[1567],{"type":45,"value":846},{"type":45,"value":811},{"type":40,"tag":152,"props":1570,"children":1572},{"className":1571},[],[1573],{"type":45,"value":1574},"_pb2.py",{"type":45,"value":796},{"type":40,"tag":152,"props":1577,"children":1579},{"className":1578},[],[1580],{"type":45,"value":1581},"*.min.js",{"type":45,"value":796},{"type":40,"tag":152,"props":1584,"children":1586},{"className":1585},[],[1587],{"type":45,"value":1588},"AssemblyInfo.cs",{"type":45,"value":1590},", …).",{"type":40,"tag":255,"props":1592,"children":1593},{},[1594,1599,1601,1607],{"type":40,"tag":79,"props":1595,"children":1596},{},[1597],{"type":45,"value":1598},"Language detection",{"type":45,"value":1600}," — ",{"type":40,"tag":152,"props":1602,"children":1604},{"className":1603},[],[1605],{"type":45,"value":1606},"detect_language_from_path",{"type":45,"value":1608}," maps the extension to a\nsupported language; unknown extensions are skipped.",{"type":40,"tag":255,"props":1610,"children":1611},{},[1612,1617,1619],{"type":40,"tag":79,"props":1613,"children":1614},{},[1615],{"type":45,"value":1616},"Test-vs-source classification",{"type":45,"value":1618}," — per-language path heuristics:",{"type":40,"tag":105,"props":1620,"children":1621},{},[1622,1638],{"type":40,"tag":109,"props":1623,"children":1624},{},[1625],{"type":40,"tag":113,"props":1626,"children":1627},{},[1628,1633],{"type":40,"tag":117,"props":1629,"children":1630},{},[1631],{"type":45,"value":1632},"Language",{"type":40,"tag":117,"props":1634,"children":1635},{},[1636],{"type":45,"value":1637},"Test rule",{"type":40,"tag":133,"props":1639,"children":1640},{},[1641,1693,1755,1775,1814,1839,1896],{"type":40,"tag":113,"props":1642,"children":1643},{},[1644,1649],{"type":40,"tag":140,"props":1645,"children":1646},{},[1647],{"type":45,"value":1648},"Python",{"type":40,"tag":140,"props":1650,"children":1651},{},[1652,1654,1660,1662,1668,1670,1676,1678,1684,1686,1692],{"type":45,"value":1653},"path contains ",{"type":40,"tag":152,"props":1655,"children":1657},{"className":1656},[],[1658],{"type":45,"value":1659},"tests\u002F",{"type":45,"value":1661},"\u002F",{"type":40,"tag":152,"props":1663,"children":1665},{"className":1664},[],[1666],{"type":45,"value":1667},"test\u002F",{"type":45,"value":1669},"; or filename starts with ",{"type":40,"tag":152,"props":1671,"children":1673},{"className":1672},[],[1674],{"type":45,"value":1675},"test_",{"type":45,"value":1677}," or ends ",{"type":40,"tag":152,"props":1679,"children":1681},{"className":1680},[],[1682],{"type":45,"value":1683},"_test.py",{"type":45,"value":1685},"; or ",{"type":40,"tag":152,"props":1687,"children":1689},{"className":1688},[],[1690],{"type":45,"value":1691},"conftest.py",{"type":45,"value":200},{"type":40,"tag":113,"props":1694,"children":1695},{},[1696,1701],{"type":40,"tag":140,"props":1697,"children":1698},{},[1699],{"type":45,"value":1700},"JS\u002FTS\u002FTSX",{"type":40,"tag":140,"props":1702,"children":1703},{},[1704,1705,1711,1712,1718,1719,1725,1726,1732,1733,1739,1741,1747,1748,1754],{"type":45,"value":1653},{"type":40,"tag":152,"props":1706,"children":1708},{"className":1707},[],[1709],{"type":45,"value":1710},"__tests__",{"type":45,"value":796},{"type":40,"tag":152,"props":1713,"children":1715},{"className":1714},[],[1716],{"type":45,"value":1717},"tests",{"type":45,"value":796},{"type":40,"tag":152,"props":1720,"children":1722},{"className":1721},[],[1723],{"type":45,"value":1724},"test",{"type":45,"value":796},{"type":40,"tag":152,"props":1727,"children":1729},{"className":1728},[],[1730],{"type":45,"value":1731},"spec",{"type":45,"value":796},{"type":40,"tag":152,"props":1734,"children":1736},{"className":1735},[],[1737],{"type":45,"value":1738},"e2e",{"type":45,"value":1740},"; or filename contains ",{"type":40,"tag":152,"props":1742,"children":1744},{"className":1743},[],[1745],{"type":45,"value":1746},".test.",{"type":45,"value":1661},{"type":40,"tag":152,"props":1749,"children":1751},{"className":1750},[],[1752],{"type":45,"value":1753},".spec.",{"type":45,"value":200},{"type":40,"tag":113,"props":1756,"children":1757},{},[1758,1763],{"type":40,"tag":140,"props":1759,"children":1760},{},[1761],{"type":45,"value":1762},"Go",{"type":40,"tag":140,"props":1764,"children":1765},{},[1766,1768,1774],{"type":45,"value":1767},"filename ends ",{"type":40,"tag":152,"props":1769,"children":1771},{"className":1770},[],[1772],{"type":45,"value":1773},"_test.go",{"type":45,"value":200},{"type":40,"tag":113,"props":1776,"children":1777},{},[1778,1783],{"type":40,"tag":140,"props":1779,"children":1780},{},[1781],{"type":45,"value":1782},"Java",{"type":40,"tag":140,"props":1784,"children":1785},{},[1786,1787,1792,1793,1798,1800,1806,1807,1813],{"type":45,"value":1653},{"type":40,"tag":152,"props":1788,"children":1790},{"className":1789},[],[1791],{"type":45,"value":1724},{"type":45,"value":1661},{"type":40,"tag":152,"props":1794,"children":1796},{"className":1795},[],[1797],{"type":45,"value":1717},{"type":45,"value":1799},"; or filename ends ",{"type":40,"tag":152,"props":1801,"children":1803},{"className":1802},[],[1804],{"type":45,"value":1805},"Test.java",{"type":45,"value":1661},{"type":40,"tag":152,"props":1808,"children":1810},{"className":1809},[],[1811],{"type":45,"value":1812},"Tests.java",{"type":45,"value":200},{"type":40,"tag":113,"props":1815,"children":1816},{},[1817,1822],{"type":40,"tag":140,"props":1818,"children":1819},{},[1820],{"type":45,"value":1821},"Rust",{"type":40,"tag":140,"props":1823,"children":1824},{},[1825,1826,1831,1832,1838],{"type":45,"value":1653},{"type":40,"tag":152,"props":1827,"children":1829},{"className":1828},[],[1830],{"type":45,"value":1659},{"type":45,"value":1661},{"type":40,"tag":152,"props":1833,"children":1835},{"className":1834},[],[1836],{"type":45,"value":1837},"benches\u002F",{"type":45,"value":200},{"type":40,"tag":113,"props":1840,"children":1841},{},[1842,1847],{"type":40,"tag":140,"props":1843,"children":1844},{},[1845],{"type":45,"value":1846},"C#",{"type":40,"tag":140,"props":1848,"children":1849},{},[1850,1851,1856,1858,1863,1864,1869,1870,1875,1876,1881,1882,1888,1889,1895],{"type":45,"value":1653},{"type":40,"tag":152,"props":1852,"children":1854},{"className":1853},[],[1855],{"type":45,"value":1659},{"type":45,"value":1857},"; or project segment ends ",{"type":40,"tag":152,"props":1859,"children":1861},{"className":1860},[],[1862],{"type":45,"value":879},{"type":45,"value":1661},{"type":40,"tag":152,"props":1865,"children":1867},{"className":1866},[],[1868],{"type":45,"value":886},{"type":45,"value":1661},{"type":40,"tag":152,"props":1871,"children":1873},{"className":1872},[],[1874],{"type":45,"value":893},{"type":45,"value":1661},{"type":40,"tag":152,"props":1877,"children":1879},{"className":1878},[],[1880],{"type":45,"value":900},{"type":45,"value":1799},{"type":40,"tag":152,"props":1883,"children":1885},{"className":1884},[],[1886],{"type":45,"value":1887},"Tests",{"type":45,"value":1661},{"type":40,"tag":152,"props":1890,"children":1892},{"className":1891},[],[1893],{"type":45,"value":1894},"Test",{"type":45,"value":200},{"type":40,"tag":113,"props":1897,"children":1898},{},[1899,1904],{"type":40,"tag":140,"props":1900,"children":1901},{},[1902],{"type":45,"value":1903},"Ruby",{"type":40,"tag":140,"props":1905,"children":1906},{},[1907,1908,1914,1915,1920,1921,1927,1928,1934],{"type":45,"value":1653},{"type":40,"tag":152,"props":1909,"children":1911},{"className":1910},[],[1912],{"type":45,"value":1913},"spec\u002F",{"type":45,"value":1661},{"type":40,"tag":152,"props":1916,"children":1918},{"className":1917},[],[1919],{"type":45,"value":1667},{"type":45,"value":1799},{"type":40,"tag":152,"props":1922,"children":1924},{"className":1923},[],[1925],{"type":45,"value":1926},"_spec.rb",{"type":45,"value":1661},{"type":40,"tag":152,"props":1929,"children":1931},{"className":1930},[],[1932],{"type":45,"value":1933},"_test.rb",{"type":45,"value":200},{"type":40,"tag":255,"props":1936,"children":1937},{},[1938,1943,1944,1950],{"type":40,"tag":79,"props":1939,"children":1940},{},[1941],{"type":45,"value":1942},"Per-file extraction",{"type":45,"value":1600},{"type":40,"tag":152,"props":1945,"children":1947},{"className":1946},[],[1948],{"type":45,"value":1949},"process(text, ProcessConfig(structure, imports, symbols))",{"type":45,"value":1951}," returns declared items, raw import statements, and a flat declared\n-name list.",{"type":40,"tag":255,"props":1953,"children":1954},{},[1955,1960,1962,1967,1969,1975,1977,1983,1985,1991,1993,1999,2001,2006,2008,2013],{"type":40,"tag":79,"props":1956,"children":1957},{},[1958],{"type":45,"value":1959},"Pairing",{"type":45,"value":1961}," — for each test file, union ",{"type":40,"tag":79,"props":1963,"children":1964},{},[1965],{"type":45,"value":1966},"import resolution",{"type":45,"value":1968}," (per language,\ne.g. Python ",{"type":40,"tag":152,"props":1970,"children":1972},{"className":1971},[],[1973],{"type":45,"value":1974},"from pkg.mod import x",{"type":45,"value":1976}," → ",{"type":40,"tag":152,"props":1978,"children":1980},{"className":1979},[],[1981],{"type":45,"value":1982},"pkg\u002Fmod.py",{"type":45,"value":1984},"; Java ",{"type":40,"tag":152,"props":1986,"children":1988},{"className":1987},[],[1989],{"type":45,"value":1990},"import a.b.C;",{"type":45,"value":1992}," →\n",{"type":40,"tag":152,"props":1994,"children":1996},{"className":1995},[],[1997],{"type":45,"value":1998},"a\u002Fb\u002FC.java",{"type":45,"value":2000},"; C# ",{"type":40,"tag":152,"props":2002,"children":2004},{"className":2003},[],[2005],{"type":45,"value":1037},{"type":45,"value":2007}," is namespace-not-file, so a no-op) with ",{"type":40,"tag":79,"props":2009,"children":2010},{},[2011],{"type":45,"value":2012},"identifier\noverlap",{"type":45,"value":2014}," (word-like tokens, length ≥ 4, matched against declared names).",{"type":40,"tag":255,"props":2016,"children":2017},{},[2018,2022,2023,2029],{"type":40,"tag":79,"props":2019,"children":2020},{},[2021],{"type":45,"value":1108},{"type":45,"value":1600},{"type":40,"tag":152,"props":2024,"children":2026},{"className":2025},[],[2027],{"type":45,"value":2028},"untested_sources",{"type":45,"value":2030}," ordered by declaration count descending.",{"type":40,"tag":48,"props":2032,"children":2034},{"id":2033},"limitations-be-honest-with-the-agent",[2035],{"type":45,"value":2036},"Limitations (be honest with the agent)",{"type":40,"tag":55,"props":2038,"children":2039},{},[2040],{"type":45,"value":2041},"Both engines are static, parse-only heuristics that trade a little accuracy for\norders-of-magnitude lower cost than coverage. Known gaps:",{"type":40,"tag":295,"props":2043,"children":2044},{},[2045,2055,2065,2089,2120],{"type":40,"tag":255,"props":2046,"children":2047},{},[2048,2053],{"type":40,"tag":79,"props":2049,"children":2050},{},[2051],{"type":45,"value":2052},"Reflection \u002F DI-resolved types",{"type":45,"value":2054}," referenced only via a string name or\ncontainer resolution won't be detected — the type's short name never appears\nin the test source.",{"type":40,"tag":255,"props":2056,"children":2057},{},[2058,2063],{"type":40,"tag":79,"props":2059,"children":2060},{},[2061],{"type":45,"value":2062},"Extension methods",{"type":45,"value":2064}," invoked as instance methods (C#): the declaring static\nclass is not named, so its file is not credited.",{"type":40,"tag":255,"props":2066,"children":2067},{},[2068,2087],{"type":40,"tag":79,"props":2069,"children":2070},{},[2071,2077,2079,2085],{"type":40,"tag":152,"props":2072,"children":2074},{"className":2073},[],[2075],{"type":45,"value":2076},"var",{"type":45,"value":2078},", target-typed ",{"type":40,"tag":152,"props":2080,"children":2082},{"className":2081},[],[2083],{"type":45,"value":2084},"new()",{"type":45,"value":2086},", pattern matching",{"type":45,"value":2088}," lose the type token; the\nfile-level union usually still catches it through other references.",{"type":40,"tag":255,"props":2090,"children":2091},{},[2092,2097,2099,2105,2106,2112,2113,2119],{"type":40,"tag":79,"props":2093,"children":2094},{},[2095],{"type":45,"value":2096},"Short identifier names",{"type":45,"value":2098}," (polyglot, \u003C 4 chars) are dropped to avoid noisy\npairings on names like ",{"type":40,"tag":152,"props":2100,"children":2102},{"className":2101},[],[2103],{"type":45,"value":2104},"id",{"type":45,"value":796},{"type":40,"tag":152,"props":2107,"children":2109},{"className":2108},[],[2110],{"type":45,"value":2111},"db",{"type":45,"value":796},{"type":40,"tag":152,"props":2114,"children":2116},{"className":2115},[],[2117],{"type":45,"value":2118},"Tag",{"type":45,"value":200},{"type":40,"tag":255,"props":2121,"children":2122},{},[2123,2128],{"type":40,"tag":79,"props":2124,"children":2125},{},[2126],{"type":45,"value":2127},"Monorepo path aliases",{"type":45,"value":2129}," (TS path mapping, Java module-info) are not\nresolved; a suffix-match fallback may pick the wrong source if two files share\na trailing path segment.",{"type":40,"tag":55,"props":2131,"children":2132},{},[2133,2135,2140],{"type":45,"value":2134},"For these cases, run actual coverage (",{"type":40,"tag":152,"props":2136,"children":2138},{"className":2137},[],[2139],{"type":45,"value":342},{"type":45,"value":2141},") on the unpaired\ncandidates the agent has already triaged.",{"type":40,"tag":55,"props":2143,"children":2144},{},[2145],{"type":45,"value":2146},"Always label the final result as a static pairing heuristic, not evidence of\nline or branch coverage. Include that caveat even when every requested source\nfile has an obvious matching or missing test.",{"type":40,"tag":48,"props":2148,"children":2150},{"id":2149},"outputs-the-agent-should-consume",[2151],{"type":45,"value":2152},"Outputs the agent should consume",{"type":40,"tag":295,"props":2154,"children":2155},{},[2156,2174,2200,2225],{"type":40,"tag":255,"props":2157,"children":2158},{},[2159,2165,2166,2172],{"type":40,"tag":152,"props":2160,"children":2162},{"className":2161},[],[2163],{"type":45,"value":2164},"untested[*].source",{"type":45,"value":1006},{"type":40,"tag":152,"props":2167,"children":2169},{"className":2168},[],[2170],{"type":45,"value":2171},"untested_sources[*].path",{"type":45,"value":2173}," — pick the next source file\nto test (highest declaration count first).",{"type":40,"tag":255,"props":2175,"children":2176},{},[2177,2183,2185,2190,2192,2198],{"type":40,"tag":152,"props":2178,"children":2180},{"className":2179},[],[2181],{"type":45,"value":2182},"*.suggested_test_path",{"type":45,"value":2184}," — drop-in target for the new test file; the Roslyn\nengine honors the test project that already ",{"type":40,"tag":152,"props":2186,"children":2188},{"className":2187},[],[2189],{"type":45,"value":1098},{"type":45,"value":2191},"s the source's\nproject, so ",{"type":40,"tag":152,"props":2193,"children":2195},{"className":2194},[],[2196],{"type":45,"value":2197},"dotnet sln add",{"type":45,"value":2199}," is not needed. The polyglot engine may suggest a\nco-located test when no test root is discoverable; that is a valid fallback,\nbut prefer an established repository test directory when one exists.",{"type":40,"tag":255,"props":2201,"children":2202},{},[2203,2209,2211,2216,2218,2223],{"type":40,"tag":152,"props":2204,"children":2206},{"className":2205},[],[2207],{"type":45,"value":2208},"source_to_tests",{"type":45,"value":2210}," (Roslyn) \u002F ",{"type":40,"tag":152,"props":2212,"children":2214},{"className":2213},[],[2215],{"type":45,"value":270},{"type":45,"value":2217}," ",{"type":40,"tag":152,"props":2219,"children":2221},{"className":2220},[],[2222],{"type":45,"value":1269},{"type":45,"value":2224}," (polyglot) —\nverify a newly written test file lands in the list for the intended source.",{"type":40,"tag":255,"props":2226,"children":2227},{},[2228,2234],{"type":40,"tag":152,"props":2229,"children":2231},{"className":2230},[],[2232],{"type":45,"value":2233},"orphan_tests",{"type":45,"value":2235}," (polyglot) — tests that don't reference any same-language\nsource file; useful for triaging stale or integration-only tests.",{"type":40,"tag":2237,"props":2238,"children":2239},"style",{},[2240],{"type":45,"value":2241},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":2243,"total":2401},[2244,2260,2273,2288,2306,2317,2336,2346,2357,2367,2380,2391],{"slug":2245,"name":2245,"fn":2246,"description":2247,"org":2248,"tags":2249,"stars":2257,"repoUrl":2258,"updatedAt":2259},"multithreaded-task-migration","migrate MSBuild tasks to multithreaded mode","Guide for migrating MSBuild tasks to multithreaded mode support, including compatibility red-team review. Use this when converting tasks to thread-safe versions, implementing IMultiThreadableTask, adding TaskEnvironment support, or auditing migrations for behavioral compatibility.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2250,2251,2254],{"name":13,"slug":14,"type":15},{"name":2252,"slug":2253,"type":15},"Engineering","engineering",{"name":2255,"slug":2256,"type":15},"Performance","performance",5535,"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fmsbuild","2026-07-22T05:37:33.965588",{"slug":2261,"name":2261,"fn":2262,"description":2263,"org":2264,"tags":2265,"stars":22,"repoUrl":23,"updatedAt":2272},"analyzing-dotnet-performance","analyze .NET code for performance anti-patterns","Scans .NET code for ~50 performance anti-patterns across async, memory, strings, collections, LINQ, regex, serialization, and I\u002FO with tiered severity classification. Use when analyzing .NET code for optimization opportunities, reviewing hot paths, or auditing allocation-heavy patterns.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2266,2267,2268,2271],{"name":13,"slug":14,"type":15},{"name":17,"slug":18,"type":15},{"name":2269,"slug":2270,"type":15},"Debugging","debugging",{"name":2255,"slug":2256,"type":15},"2026-07-12T08:23:25.400375",{"slug":2274,"name":2274,"fn":2275,"description":2276,"org":2277,"tags":2278,"stars":22,"repoUrl":23,"updatedAt":2287},"android-tombstone-symbolication","symbolicate .NET runtime frames in Android tombstones","Symbolicate the .NET runtime frames in an Android tombstone file. Extracts BuildIds and PC offsets from the native backtrace, downloads debug symbols from the Microsoft symbol server, and runs llvm-symbolizer to produce function names with source file and line numbers. USE FOR triaging a .NET MAUI or Mono Android app crash from a tombstone, resolving native backtrace frames in libmonosgen-2.0.so or libcoreclr.so to .NET runtime source code, or investigating SIGABRT, SIGSEGV, or other native signals originating from the .NET runtime on Android. DO NOT USE FOR pure Java\u002FKotlin crashes, managed .NET exceptions that are already captured in logcat, or iOS crash logs. INVOKES Symbolicate-Tombstone.ps1 script, llvm-symbolizer, Microsoft symbol server.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2279,2280,2283,2284],{"name":13,"slug":14,"type":15},{"name":2281,"slug":2282,"type":15},"Android","android",{"name":2269,"slug":2270,"type":15},{"name":2285,"slug":2286,"type":15},"Microsoft","microsoft","2026-07-12T08:23:21.595572",{"slug":2289,"name":2289,"fn":2290,"description":2291,"org":2292,"tags":2293,"stars":22,"repoUrl":23,"updatedAt":2305},"apple-crash-symbolication","symbolicate .NET runtime frames in crash logs","Symbolicate .NET runtime frames in Apple platform .ips crash logs (iOS, tvOS, Mac Catalyst, macOS). Extracts UUIDs and addresses from the native backtrace, locates dSYM debug symbols, and runs atos to produce function names with source file and line numbers. Automatically downloads .dwarf symbols from the Microsoft symbol server using Mach-O UUIDs. USE FOR triaging a .NET MAUI or Mono app crash from an .ips file on any Apple platform, resolving native backtrace frames in libcoreclr or libmonosgen-2.0 to .NET runtime source code, retrieving .ips crash logs from a connected iOS device or iPhone, or investigating EXC_CRASH, EXC_BAD_ACCESS, SIGABRT, or SIGSEGV originating from the .NET runtime. DO NOT USE FOR pure Swift\u002FObjective-C crashes with no .NET components, or Android tombstone files. INVOKES Symbolicate-Crash.ps1 script, atos, dwarfdump, idevicecrashreport.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2294,2295,2296,2299,2302],{"name":13,"slug":14,"type":15},{"name":2269,"slug":2270,"type":15},{"name":2297,"slug":2298,"type":15},"iOS","ios",{"name":2300,"slug":2301,"type":15},"macOS","macos",{"name":2303,"slug":2304,"type":15},"Observability","observability","2026-07-12T08:23:20.369986",{"slug":381,"name":381,"fn":2307,"description":2308,"org":2309,"tags":2310,"stars":22,"repoUrl":23,"updatedAt":2316},"evaluate assertion quality in test suites","Analyzes the variety and depth of assertions across test suites in any language. Use when the user asks to evaluate assertion quality, find shallow tests, identify assertion-free tests (no assertions or only trivial ones like Assert.IsNotNull \u002F toBeTruthy()), flag self-referential or tautological assertions, measure assertion diversity, or audit whether tests verify different facets of behavior. Polyglot: .NET, Python, TS\u002FJS, Java, Go, Ruby, Rust, Swift, Kotlin, PowerShell, C++. DO NOT USE FOR: writing new tests (use code-testing-agent \u002F writing-mstest-tests), mutation reasoning about whether tests would catch a bug (use test-gap-analysis), or a general severity-ranked anti-pattern audit (use test-anti-patterns), fixing or rewriting assertions, or writing, fixing, or modernizing MSTest tests, assertions, or attributes (use writing-mstest-tests).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2311,2312,2315],{"name":17,"slug":18,"type":15},{"name":2313,"slug":2314,"type":15},"QA","qa",{"name":20,"slug":21,"type":15},"2026-07-12T08:23:51.277743",{"slug":2318,"name":2318,"fn":2319,"description":2320,"org":2321,"tags":2322,"stars":22,"repoUrl":23,"updatedAt":2335},"author-component","create and review Blazor components","Create or review Blazor components (.razor files) with correct architecture. USE FOR: writing new Blazor components that do NOT involve JavaScript interop, implementing parameters and EventCallback, RenderFragment slots, component lifecycle (OnInitializedAsync, OnParametersSet), async patterns, IAsyncDisposable, CancellationToken, CSS isolation, code-behind. DO NOT USE FOR: creating new projects (use create-blazor-project), JavaScript interop or calling browser APIs from Blazor (use use-js-interop), forms and validation (use collect-user-input), prerendering issues (use support-prerendering), HTTP data fetching patterns (use fetch-and-send-data), coordinating state between unrelated components (use coordinate-components).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2323,2324,2327,2329,2332],{"name":13,"slug":14,"type":15},{"name":2325,"slug":2326,"type":15},"Blazor","blazor",{"name":1846,"slug":2328,"type":15},"csharp",{"name":2330,"slug":2331,"type":15},"UI Components","ui-components",{"name":2333,"slug":2334,"type":15},"Web Development","web-development","2026-07-15T06:03:29.216359",{"slug":2337,"name":2337,"fn":2338,"description":2339,"org":2340,"tags":2341,"stars":22,"repoUrl":23,"updatedAt":2345},"binlog-failure-analysis","analyze MSBuild binary logs","Analyze MSBuild binary logs to diagnose build failures. USE FOR: build errors that are unclear from console output, diagnosing cascading failures across multi-project builds, tracing MSBuild target execution order, and generally any MSBuild build issues. Requires an existing .binlog file. DO NOT USE FOR: generating binlogs (use binlog-generation), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2342,2343,2344],{"name":17,"slug":18,"type":15},{"name":2269,"slug":2270,"type":15},{"name":2285,"slug":2286,"type":15},"2026-07-12T08:21:34.637923",{"slug":2347,"name":2347,"fn":2348,"description":2349,"org":2350,"tags":2351,"stars":22,"repoUrl":23,"updatedAt":2356},"binlog-generation","generate MSBuild binary logs for diagnostics","Generate MSBuild binary logs (binlogs) for build diagnostics and analysis. USE FOR: adding \u002Fbl:{} to any dotnet build, test, pack, publish, or restore command to capture a full build execution trace, prerequisite for binlog-failure-analysis and build-perf-diagnostics skills, enabling post-build investigation of errors or performance. Requires MSBuild 17.8+ \u002F .NET 8 SDK+ for {} placeholder; PowerShell needs -bl:{{}}. DO NOT USE FOR: non-MSBuild build systems (npm, Maven, CMake), analyzing an existing binlog (use binlog-failure-analysis instead).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2352,2354,2355],{"name":2353,"slug":1519,"type":15},"Build",{"name":2269,"slug":2270,"type":15},{"name":2252,"slug":2253,"type":15},"2026-07-19T05:38:19.340791",{"slug":2358,"name":2358,"fn":2359,"description":2360,"org":2361,"tags":2362,"stars":22,"repoUrl":23,"updatedAt":2366},"build-parallelism","optimize MSBuild build parallelism","Diagnose and fix under-parallelized MSBuild builds. USE WHEN a multi-project solution build is slower than expected, doesn't speed up when you add cores, pegs a single core while others idle, or you want to know why `-m` isn't helping. Note: `\u002Fmaxcpucount` default is 1 (sequential) — always pass `-m` for parallel builds. Covers finding the critical path (longest serial ProjectReference chain), graph build (`\u002Fgraph`), BuildInParallel, and solution filters (`.slnf`). DO NOT USE FOR: single-project builds, incremental issues (use incremental-build), compilation slowness inside one project (use build-perf-diagnostics), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2363,2364,2365],{"name":13,"slug":14,"type":15},{"name":2252,"slug":2253,"type":15},{"name":2255,"slug":2256,"type":15},"2026-07-19T05:38:18.364937",{"slug":2368,"name":2368,"fn":2369,"description":2370,"org":2371,"tags":2372,"stars":22,"repoUrl":23,"updatedAt":2379},"build-perf-baseline","establish and optimize build performance baselines","Establish build performance baselines and apply systematic optimization techniques. USE FOR: diagnosing slow builds, establishing before\u002Fafter measurements (cold, warm, no-op scenarios), applying optimization strategies like MSBuild Server, static graph builds, artifacts output, and dependency graph trimming. Start here before diving into build-perf-diagnostics, incremental-build, or build-parallelism. DO NOT USE FOR: non-MSBuild build systems, detailed bottleneck analysis (use build-perf-diagnostics after baselining).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2373,2374,2377,2378],{"name":2252,"slug":2253,"type":15},{"name":2375,"slug":2376,"type":15},"Monitoring","monitoring",{"name":2255,"slug":2256,"type":15},{"name":20,"slug":21,"type":15},"2026-07-12T08:21:35.865649",{"slug":2381,"name":2381,"fn":2382,"description":2383,"org":2384,"tags":2385,"stars":22,"repoUrl":23,"updatedAt":2390},"build-perf-diagnostics","diagnose MSBuild build performance bottlenecks","Diagnose MSBuild build performance bottlenecks using binary log analysis. USE FOR: identifying why builds are slow by analyzing binlog performance summaries, detecting ResolveAssemblyReference (RAR) taking >5s, Roslyn analyzers consuming >30% of Csc time, single targets dominating >50% of build time, node utilization below 80%, excessive Copy tasks, NuGet restore running every build. Covers timeline analysis, Target\u002FTask Performance Summary interpretation, and 7 common bottleneck categories. Use after build-perf-baseline has established measurements. DO NOT USE FOR: establishing initial baselines (use build-perf-baseline first), fixing incremental build issues (use incremental-build), parallelism tuning (use build-parallelism), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2386,2387,2388,2389],{"name":13,"slug":14,"type":15},{"name":2269,"slug":2270,"type":15},{"name":2252,"slug":2253,"type":15},{"name":2255,"slug":2256,"type":15},"2026-07-12T08:21:40.961722",{"slug":2392,"name":2392,"fn":2393,"description":2394,"org":2395,"tags":2396,"stars":22,"repoUrl":23,"updatedAt":2400},"check-bin-obj-clash","detect MSBuild output path conflicts","Detects MSBuild projects with conflicting OutputPath or IntermediateOutputPath. USE FOR: builds failing with 'Cannot create a file when that file already exists', 'The process cannot access the file because it is being used by another process', intermittent build failures that succeed on retry, or missing\u002Foverwritten outputs in multi-project or multi-targeting builds where bin\u002Fobj (or project.assets.json) collide. Common causes: shared OutputPath, missing AppendTargetFrameworkToOutputPath, extra global properties (e.g. PublishReadyToRun), or SetTargetFramework on a ProjectReference to a single-targeting project. DO NOT USE FOR: file access errors unrelated to MSBuild (OS-level locking), single-project single-TFM builds, non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2397,2398,2399],{"name":2269,"slug":2270,"type":15},{"name":2252,"slug":2253,"type":15},{"name":2313,"slug":2314,"type":15},"2026-07-19T05:38:14.336279",144,{"items":2403,"total":2452},[2404,2411,2418,2426,2432,2440,2446],{"slug":2261,"name":2261,"fn":2262,"description":2263,"org":2405,"tags":2406,"stars":22,"repoUrl":23,"updatedAt":2272},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2407,2408,2409,2410],{"name":13,"slug":14,"type":15},{"name":17,"slug":18,"type":15},{"name":2269,"slug":2270,"type":15},{"name":2255,"slug":2256,"type":15},{"slug":2274,"name":2274,"fn":2275,"description":2276,"org":2412,"tags":2413,"stars":22,"repoUrl":23,"updatedAt":2287},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2414,2415,2416,2417],{"name":13,"slug":14,"type":15},{"name":2281,"slug":2282,"type":15},{"name":2269,"slug":2270,"type":15},{"name":2285,"slug":2286,"type":15},{"slug":2289,"name":2289,"fn":2290,"description":2291,"org":2419,"tags":2420,"stars":22,"repoUrl":23,"updatedAt":2305},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2421,2422,2423,2424,2425],{"name":13,"slug":14,"type":15},{"name":2269,"slug":2270,"type":15},{"name":2297,"slug":2298,"type":15},{"name":2300,"slug":2301,"type":15},{"name":2303,"slug":2304,"type":15},{"slug":381,"name":381,"fn":2307,"description":2308,"org":2427,"tags":2428,"stars":22,"repoUrl":23,"updatedAt":2316},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2429,2430,2431],{"name":17,"slug":18,"type":15},{"name":2313,"slug":2314,"type":15},{"name":20,"slug":21,"type":15},{"slug":2318,"name":2318,"fn":2319,"description":2320,"org":2433,"tags":2434,"stars":22,"repoUrl":23,"updatedAt":2335},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2435,2436,2437,2438,2439],{"name":13,"slug":14,"type":15},{"name":2325,"slug":2326,"type":15},{"name":1846,"slug":2328,"type":15},{"name":2330,"slug":2331,"type":15},{"name":2333,"slug":2334,"type":15},{"slug":2337,"name":2337,"fn":2338,"description":2339,"org":2441,"tags":2442,"stars":22,"repoUrl":23,"updatedAt":2345},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2443,2444,2445],{"name":17,"slug":18,"type":15},{"name":2269,"slug":2270,"type":15},{"name":2285,"slug":2286,"type":15},{"slug":2347,"name":2347,"fn":2348,"description":2349,"org":2447,"tags":2448,"stars":22,"repoUrl":23,"updatedAt":2356},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2449,2450,2451],{"name":2353,"slug":1519,"type":15},{"name":2269,"slug":2270,"type":15},{"name":2252,"slug":2253,"type":15},96]