Captain Obvious Deletes tests that assert what is already guaranteed — by the compiler, by the mock framework, or by the laws of logic. These tests burn CI time, inflate coverage confidence, and can never catch a regression. They are the signature of AI-generated test suites (empirical studies find test smells in 38–100% of LLM-generated tests). For cleanup, two deterministic scripts in do the heavy lifting. Run them, interpret the report, clean up the residue, and verify nothing broke. Do not hand-scan test files or spawn subagents per file — one script invocation scans the whole project. Du…

)\nANY_RETURN_RE = re.compile(r'^(.*?):(\\d+):(?:\\d+:)?\\s*(?:error|warning):.*\\[no-any-return\\]\\s*

Captain Obvious Deletes tests that assert what is already guaranteed — by the compiler, by the mock framework, or by the laws of logic. These tests burn CI time, inflate coverage confidence, and can never catch a regression. They are the signature of AI-generated test suites (empirical studies find test smells in 38–100% of LLM-generated tests). For cleanup, two deterministic scripts in do the heavy lifting. Run them, interpret the report, clean up the residue, and verify nothing broke. Do not hand-scan test files or spawn subagents per file — one script invocation scans the whole project. Du…

)\n\ndef strip_generics(t: str) -> str:\n return t.split(\"[\", 1)[0]\n\n\ndef base_name(t: str) -> str:\n t = t.strip().rstrip(\"*\").strip('\"')\n if t.startswith(\"Literal[\"):\n inner = t[len(\"Literal[\"):-1]\n if inner and (inner[0] in \"'\\\"\"):\n return \"str\"\n if inner in (\"True\", \"False\"):\n return \"bool\"\n if re.fullmatch(r\"-?\\d+\", inner):\n return \"int\"\n return \"Literal\"\n t = strip_generics(t)\n return t.split(\".\")[-1]\n\n\ndef union_members(t: str) -> list[str]:\n t = t.strip().rstrip(\"*\")\n if t.startswith(\"Union[\") and t.endswith(\"]\"):\n inner, out, depth, cur = t[6:-1], [], 0, \"\"\n for ch in inner:\n if ch == \"[\":\n depth += 1\n elif ch == \"]\":\n depth -= 1\n if ch == \",\" and depth == 0:\n out.append(cur.strip())\n cur = \"\"\n else:\n cur += ch\n out.append(cur.strip())\n return out\n if \" | \" in t:\n # split on top-level pipes only\n out, depth, cur = [], 0, \"\"\n for ch in t:\n if ch == \"[\":\n depth += 1\n elif ch == \"]\":\n depth -= 1\n if ch == \"|\" and depth == 0:\n out.append(cur.strip())\n cur = \"\"\n else:\n cur += ch\n out.append(cur.strip())\n return out\n if t.startswith(\"Optional[\") and t.endswith(\"]\"):\n return [t[9:-1].strip(), \"None\"]\n return [t]\n\n\ndef enclosing_function_names(sites: set[tuple[str, int]]) -> set[str]:\n \"\"\"Map (file, line) sites to the names of their enclosing functions.\"\"\"\n names: set[str] = set()\n by_file: dict[str, list[int]] = {}\n for f, ln in sites:\n by_file.setdefault(f, []).append(ln)\n for f, lns in by_file.items():\n try:\n tree = ast.parse(open(f, encoding=\"utf-8\").read())\n except (OSError, SyntaxError):\n continue\n for n in ast.walk(tree):\n if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) and n.end_lineno:\n if any(n.lineno \u003c= ln \u003c= n.end_lineno for ln in lns):\n names.add(n.name)\n return names\n\n\ndef propagate_laundering(root: str, seed: set[str]) -> set[str]:\n \"\"\"Grow the Any-laundering function set transitively.\"\"\"\n if not seed:\n return set() # nothing to propagate — skip the whole-repo parse\n returns_calls: dict[str, set[str]] = {}\n for dirpath, dirnames, filenames in os.walk(root):\n dirnames[:] = [d for d in dirnames if d not in SKIP_DIRS and not d.startswith(\".\")]\n for fn in filenames:\n if not fn.endswith(\".py\") or fn.startswith(SHADOW_PREFIX):\n continue\n try:\n tree = ast.parse(open(os.path.join(dirpath, fn), encoding=\"utf-8\").read())\n except (OSError, SyntaxError, UnicodeDecodeError):\n continue\n for node in ast.walk(tree):\n if not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):\n continue\n for r in ast.walk(node):\n if isinstance(r, ast.Return) and r.value is not None:\n v = r.value\n if isinstance(v, ast.Await):\n v = v.value\n if isinstance(v, ast.Call):\n cn = call_name(v)\n if cn:\n returns_calls.setdefault(node.name, set()).add(cn)\n\n laundering = set(seed)\n changed = True\n while changed:\n changed = False\n for fname, callees in returns_calls.items():\n if fname not in laundering and (callees & laundering):\n laundering.add(fname)\n changed = True\n return laundering\n\n\ndef run_mypy_probes(probes: list[Probe], root: str,\n mypy_cmd: list[str] | None) -> tuple[str | None, set[str], bool]:\n \"\"\"Insert reveal_type() shadow files, run mypy once, map notes back.\n\n Returns (note, laundering_functions, laundering_visible). laundering_visible\n is False when no source targets could be found for mypy — the Any-laundering\n guard cannot run, so type-guaranteed findings must not be promoted to proven.\n \"\"\"\n if not probes:\n return None, set(), True\n by_file: dict[str, list[Probe]] = {}\n for p in probes:\n by_file.setdefault(p.file, []).append(p)\n\n shadow_map = {} # shadow_path -> {shadow_line: probe}\n shadow_files = []\n skipped_shadow = [] # basenames skipped due to a pre-existing shadow symlink\n try:\n for file, plist in by_file.items():\n src_lines = [l.rstrip(\"\\r\\n\") for l in split_lines_keepends(\n open(file, encoding=\"utf-8\", newline=\"\").read())]\n plist.sort(key=lambda p: p.line)\n out_lines, li, inserted = [], 0, 0\n line_map = {}\n for p in plist:\n while li \u003c p.line - 1:\n out_lines.append(src_lines[li])\n li += 1\n out_lines.append(\" \" * p.indent + f\"reveal_type(({p.expr_src}))\")\n inserted += 1\n line_map[len(out_lines)] = p\n out_lines.extend(src_lines[li:])\n shadow = os.path.join(os.path.dirname(file),\n SHADOW_PREFIX + os.path.basename(file))\n if os.path.islink(shadow):\n # a pre-existing symlink under the shadow name would be\n # written through — skip this file's probes instead, and\n # record it so the skip is not silent (see note below)\n skipped_shadow.append(os.path.basename(file))\n continue\n with open(shadow, \"w\", encoding=\"utf-8\") as f:\n f.write(\"\\n\".join(out_lines) + \"\\n\")\n shadow_files.append(shadow)\n shadow_map[os.path.abspath(shadow)] = line_map\n\n cmds = [mypy_cmd] if mypy_cmd else []\n if not cmds:\n if os.path.exists(os.path.join(root, \"uv.lock\")) and shutil.which(\"uv\"):\n cmds.append([\"uv\", \"run\", \"mypy\"])\n if shutil.which(\"mypy\"):\n cmds.append([\"mypy\"])\n cmds.append([sys.executable, \"-m\", \"mypy\"])\n\n # mypy only reports errors for explicitly-listed targets, so the source\n # tree must be in the run for [no-any-return] laundering detection\n src_targets = []\n if os.path.isdir(os.path.join(root, \"src\")):\n src_targets.append(os.path.join(root, \"src\"))\n else:\n for d in sorted(os.listdir(root)):\n if d in SKIP_DIRS or d.startswith(\".\") or d in (\"tests\", \"test\"):\n continue\n if os.path.isfile(os.path.join(root, d, \"__init__.py\")):\n src_targets.append(os.path.join(root, d))\n if not src_targets:\n # flat layout: top-level modules are the source tree\n for fn in sorted(os.listdir(root)):\n if fn.endswith(\".py\") and not fn.startswith(SHADOW_PREFIX) \\\n and not is_test_filename(fn):\n src_targets.append(os.path.join(root, fn))\n laundering_visible = bool(src_targets)\n\n proc = None\n usable = False\n for cmd in cmds:\n try:\n proc = subprocess.run(\n cmd + [\"--no-error-summary\", \"--no-pretty\",\n \"--check-untyped-defs\",\n \"--warn-return-any\",\n \"--show-error-codes\",\n \"--show-column-numbers\"] + shadow_files + src_targets,\n cwd=root, capture_output=True, text=True, timeout=600)\n if \"Revealed type\" in proc.stdout or proc.returncode in (0, 1):\n if \"No module named mypy\" in (proc.stderr or \"\") or \"No module named mypy\" in (proc.stdout or \"\"):\n proc = None\n continue\n usable = True\n break\n except (FileNotFoundError, subprocess.TimeoutExpired):\n proc = None\n continue\n if proc is None:\n return (\"mypy not runnable — type-guaranteed checks skipped (install mypy or pass --mypy)\",\n set(), True)\n if not usable:\n # mypy ran but exited >=2 (fatal / bad config / unreadable source).\n # Without this branch every probe keeps revealed=None, resolve_probes\n # quietly reclassifies them as nonredundant, and the whole\n # type-guaranteed category vanishes with no user-facing signal.\n detail = (proc.stderr or proc.stdout or \"\").strip().splitlines()\n first = detail[0][:200] if detail else f\"exit {proc.returncode}\"\n return (f\"mypy failed ({first}) — type-guaranteed checks skipped\", set(), True)\n\n any_return_sites: set[tuple[str, int]] = set()\n for line in proc.stdout.splitlines():\n m = REVEAL_RE.match(line)\n if m:\n fpath, lno, revealed = os.path.abspath(os.path.join(root, m.group(1))), int(m.group(2)), m.group(3)\n if fpath not in shadow_map:\n fpath = os.path.abspath(m.group(1))\n probe = shadow_map.get(fpath, {}).get(lno)\n if probe:\n probe.revealed = revealed\n continue\n m = ANY_RETURN_RE.match(line)\n if m:\n fpath = os.path.abspath(os.path.join(root, m.group(1)))\n if not os.path.exists(fpath):\n fpath = os.path.abspath(m.group(1))\n any_return_sites.add((fpath, int(m.group(2))))\n seed = enclosing_function_names(any_return_sites)\n note = None\n if not laundering_visible:\n note = (\"no source packages or top-level modules found under the project root — \"\n \"mypy cannot see the code under test, so the Any-laundering guard is \"\n \"unavailable; type-guaranteed findings demoted to advisory\")\n if skipped_shadow:\n # don't let the islink skip vanish silently — every other\n # degradation in this module says so\n skip_note = (f\"{len(skipped_shadow)} file(s) skipped for type-guaranteed \"\n f\"checks — a pre-existing shadow symlink \"\n f\"({', '.join(sorted(skipped_shadow))})\")\n note = f\"{note}; {skip_note}\" if note else skip_note\n return note, propagate_laundering(root, seed), laundering_visible\n except OSError as e:\n # e.g. read-only checkout: shadow files cannot be written next to the\n # tests. Degrade to the syntactic categories instead of crashing the\n # whole scan — and say so, like every other degradation path.\n return (f\"cannot write reveal_type() shadow files ({e}) — \"\n \"type-guaranteed checks skipped\", set(), True)\n finally:\n for s in shadow_files:\n try:\n os.remove(s)\n except OSError:\n pass\n\n\ndef resolve_probes(probes: list[Probe], records: list[TestRecord], root: str,\n laundering: set[str] | None = None,\n laundering_visible: bool = True):\n laundering = laundering or set()\n recs_by_key = {}\n for r in records:\n recs_by_key.setdefault((r.file, r.name), r)\n\n def touches_laundering(p: Probe, rec: TestRecord) -> bool:\n if not laundering:\n return False\n try:\n expr = ast.parse(p.expr_src, mode=\"eval\").body\n except SyntaxError:\n return True # can't reason — stay safe\n called = {call_name(n) for n in ast.walk(expr) if isinstance(n, ast.Call)}\n for n in ast.walk(expr):\n if isinstance(n, ast.Name):\n for d in walk_no_nested_funcs(rec.node):\n if isinstance(d, ast.Assign) and any(\n isinstance(t, ast.Name) and t.id == n.id for t in d.targets):\n called |= {call_name(c) for c in ast.walk(d.value) if isinstance(c, ast.Call)}\n return bool((called - {None}) & laundering)\n\n for p in probes:\n rec = recs_by_key.get((p.file, p.finding_slot[0]))\n if rec is None:\n continue\n a = p.finding_slot[1]\n f = None\n if p.revealed and touches_laundering(p, rec):\n rec.nonredundant += 1\n continue\n if p.revealed:\n members = union_members(p.revealed)\n bad = any(base_name(m) in (\"Any\", \"\") for m in members)\n if p.kind == \"not-none\" and not bad and \"None\" not in [base_name(m) for m in members]:\n f = Finding(p.file, p.line, rec.name, \"type-guaranteed\", \"proven\", \"safe\",\n f'mypy already guarantees non-None (revealed type: \"{p.revealed}\")', node=a)\n elif p.kind == \"isinstance\" and not bad \\\n and all(base_name(m) in p.extra for m in members):\n f = Finding(p.file, p.line, rec.name, \"type-guaranteed\", \"proven\", \"safe\",\n f'mypy already guarantees isinstance (revealed type: \"{p.revealed}\")', node=a)\n elif p.kind == \"exact-type\" and not bad and len(members) == 1 \\\n and base_name(members[0]) in p.extra:\n f = Finding(p.file, p.line, rec.name, \"type-guaranteed\", \"advisory\", \"aggressive\",\n f'revealed type is \"{p.revealed}\", but a subclass instance would still fail type() is — advisory', node=a)\n if f is not None and f.level == \"proven\" and not laundering_visible:\n # without source targets mypy never emits [no-any-return], so the\n # laundering exemption can't clear this finding — don't auto-delete\n f.level, f.deletable = \"advisory\", \"report-only\"\n f.reason += (\" — but mypy could not see the source tree, so an Any-laundering \"\n \"annotation may be behind this type; verify before removing\")\n if f is not None:\n rec.findings.append(f)\n else:\n rec.nonredundant += 1\n","content_type":"text/x-python; charset=utf-8","language":"python","size":14856,"content_sha256":"2045ce32f8e33399398c3467a383af54b3548759ac66c8b8e4b364805d99bfaf"},{"filename":"scripts/co_ts/analyzer.mjs","content":"import path from 'node:path';\nimport {\n walk,\n rootIdentifier,\n isLiteralish,\n literalValue,\n assertionMachineryNodes\n} from './ast_utils.mjs';\nimport { parseExpectation } from './expect_parser.mjs';\nimport { detectMockEcho } from './mock_echo.mjs';\nimport { classifyExpect } from './classifier.mjs';\nimport { subjectLaunders } from './laundering.mjs';\n\nexport const ASSERTION_ROOTS = new Set(['expect', 'assert', 'chai', 'sinon', 'expectTypeOf', 'assertType']);\nexport const NEUTRAL_EXPECT_STATIC = new Set(['assertions', 'hasAssertions']);\n\nexport const isAssertionRoot = (root) =>\n ASSERTION_ROOTS.has(root) || /^(expect|assert|verify|check|should)/i.test(root);\n\nexport function isOutermostAssertCall(ts, n) {\n let p = n.parent;\n while (p && (ts.isPropertyAccessExpression(p) || ts.isCallExpression(p) ||\n ts.isAwaitExpression(p) || ts.isParenthesizedExpression(p) ||\n ts.isNonNullExpression(p))) {\n if (ts.isCallExpression(p)) {\n const r = rootIdentifier(ts, p.expression);\n if (r && isAssertionRoot(r)) return false;\n }\n p = p.parent;\n }\n return true;\n}\n\nexport function isNoiseCall(ts, expr) {\n let curr = expr;\n while (curr) {\n if (ts.isCallExpression(curr) || ts.isNewExpression(curr)) {\n curr = curr.expression;\n } else if (ts.isPropertyAccessExpression(curr)) {\n const name = curr.name.text;\n if (name === 'console' || name === 'log' || name === 'logger' || name === 'logging') return true;\n curr = curr.expression;\n } else if (ts.isElementAccessExpression(curr) || ts.isNonNullExpression(curr) ||\n ts.isAwaitExpression(curr) || ts.isParenthesizedExpression(curr)) {\n curr = curr.expression;\n } else if (ts.isIdentifier(curr)) {\n const text = curr.text;\n return text === 'console' || text === 'log' || text === 'logger' || text === 'logging';\n } else if (curr.kind === ts.SyntaxKind.ThisKeyword) {\n return false;\n } else {\n break;\n }\n }\n return false;\n}\n\nexport function isTestBlock(ts, stmt) {\n if (!ts.isExpressionStatement(stmt) || !ts.isCallExpression(stmt.expression)) return null;\n const c = stmt.expression;\n let name = null, modifier = null;\n if (ts.isIdentifier(c.expression)) name = c.expression.text;\n else if (ts.isPropertyAccessExpression(c.expression) && ts.isIdentifier(c.expression.expression) &&\n ['only', 'skip', 'fails', 'concurrent', 'sequential'].includes(c.expression.name.text)) {\n name = c.expression.expression.text;\n modifier = c.expression.name.text;\n }\n if (!name || !['it', 'test', 'xit', 'fit'].includes(name)) return null;\n const fn = c.arguments.find(a => ts.isArrowFunction(a) || ts.isFunctionExpression(a));\n if (!fn) return null;\n const title = c.arguments[0] && ts.isStringLiteralLike(c.arguments[0]) ? c.arguments[0].text : '\u003cdynamic>';\n const skipped = name === 'xit' || modifier === 'skip';\n return { stmt, title, fn, skipped };\n}\n\nexport function enclosingDescribeKey(ts, node, sf) {\n let n = node.parent;\n while (n) {\n if (ts.isCallExpression(n) && rootIdentifier(ts, n.expression) === 'describe') return `${sf.fileName}#${n.pos}`;\n n = n.parent;\n }\n return `${sf.fileName}#top`;\n}\n\nexport function toReportFinding(projectDir, rec, f) {\n return {\n file: path.relative(projectDir, rec.sf.fileName),\n line: f.stmtRef ? rec.sf.getLineAndCharacterOfPosition(f.stmtRef.getStart(rec.sf)).line + 1 : (f.covLine ?? rec.line),\n test: rec.title,\n category: f.category, level: f.level, deletable: f.deletable,\n snippet: f.stmtRef ? f.stmtRef.getText(rec.sf).slice(0, 160) : undefined,\n reason: f.reason,\n };\n}\n\nexport function analyzeTest(ts, checker, typesAvailable, strictNull, uncheckedIndex, sf, tBlock, allFindings, testRecords, projectDir) {\n const { stmt, title, fn, skipped } = tBlock;\n const body = fn.body;\n const statements = ts.isBlock(body) ? [...body.statements] : [];\n const line = sf.getLineAndCharacterOfPosition(stmt.getStart(sf)).line + 1;\n const rec = { sf, stmt, title, fn, line, findings: [], expectCount: 0,\n nonRedundantExpects: 0, nestedAssertions: 0, hasAssertionCtl: false };\n\n if (skipped) {\n rec.findings.push({ category: 'skipped-test', level: 'advisory', deletable: 'aggressive',\n reason: 'test is unconditionally skipped (xit / .skip) — it never runs and can never fail', stmtRef: null });\n allFindings.push(toReportFinding(projectDir, rec, rec.findings[0]));\n testRecords.push(rec);\n return;\n }\n\n const allAssertCalls = [];\n walk(ts, fn, n => {\n if (ts.isCallExpression(n)) {\n const root = rootIdentifier(ts, n.expression);\n if (root && isAssertionRoot(root) && isOutermostAssertCall(ts, n)) allAssertCalls.push(n);\n }\n });\n\n const unreachableStmts = new Set();\n {\n let dead = false;\n for (const s of statements) {\n if (dead) unreachableStmts.add(s);\n if (ts.isReturnStatement(s) || ts.isThrowStatement(s)) dead = true;\n }\n }\n\n for (const s of statements) {\n if (unreachableStmts.has(s)) {\n let isFail = false;\n if (ts.isThrowStatement(s)) isFail = true;\n else if (ts.isExpressionStatement(s) && ts.isCallExpression(s.expression)) {\n const root = rootIdentifier(ts, s.expression.expression);\n if (root === 'fail') isFail = true;\n }\n if (isFail) {\n rec.findings.push({ category: 'missed-fail', level: 'proven', deletable: 'report-only', stmtRef: s,\n reason: 'fail marker sits after an unconditional return/throw — it can never fire' });\n }\n }\n }\n const topStatementOf = (node) => {\n let n = node;\n while (n && n.parent !== body) n = n.parent;\n return n;\n };\n\n const swallowed = new Set();\n // Everything lexically inside a try{} whose catch is silent: if it throws,\n // the catch absorbs it, so it can never fail the test and therefore never\n // counts as coverage worth preserving.\n const silentlyGuarded = new Set();\n walk(ts, fn, n => {\n if (ts.isTryStatement(n) && n.catchClause && isSilentCatch(ts, n.catchClause)) {\n walk(ts, n, m => silentlyGuarded.add(m));\n walk(ts, n.tryBlock, m => {\n if (ts.isCallExpression(m)) {\n const root = rootIdentifier(ts, m.expression);\n if (root && isAssertionRoot(root) && isOutermostAssertCall(ts, m)) swallowed.add(m);\n }\n });\n }\n });\n\n // helper to check if try statement's catch block is silent\n function isSilentCatch(ts, catchClause) {\n return catchClause.block.statements.every(s =>\n ts.isExpressionStatement(s) && ts.isCallExpression(s.expression) &&\n rootIdentifier(ts, s.expression.expression) === 'console');\n }\n\n for (const s of statements) {\n if (ts.isExpressionStatement(s) && ts.isCallExpression(s.expression) &&\n ts.isPropertyAccessExpression(s.expression.expression) &&\n ts.isIdentifier(s.expression.expression.expression) &&\n s.expression.expression.expression.text === 'expect' &&\n NEUTRAL_EXPECT_STATIC.has(s.expression.expression.name.text)) {\n rec.hasAssertionCtl = true;\n }\n }\n\n const realAsserts = allAssertCalls.filter(c => {\n if (ts.isPropertyAccessExpression(c.expression) &&\n ts.isIdentifier(c.expression.expression) && c.expression.expression.text === 'expect' &&\n NEUTRAL_EXPECT_STATIC.has(c.expression.name.text)) return false;\n return true;\n });\n const liveAsserts = realAsserts.filter(c =>\n !swallowed.has(c) && !unreachableStmts.has(topStatementOf(c)));\n\n for (const c of swallowed) {\n if (!realAsserts.includes(c)) continue;\n const cline = sf.getLineAndCharacterOfPosition(c.getStart(sf)).line + 1;\n rec.findings.push({ category: 'swallowed-assert', level: 'proven', deletable: 'report-only',\n reason: `assertion at line ${cline} sits in a try{} with a silent catch — a failure is swallowed, it can never fail the test`, stmtRef: null });\n }\n\n if (realAsserts.length === 0) {\n\n let hasCalls = false;\n let allCallsGuarded = true;\n walk(ts, body, n => {\n if (ts.isCallExpression(n) || ts.isNewExpression(n)) {\n if (!isNoiseCall(ts, n)) {\n hasCalls = true;\n if (!silentlyGuarded.has(n)) {\n allCallsGuarded = false;\n }\n }\n }\n });\n\n if (hasCalls && allCallsGuarded) {\n rec.findings.push({ category: 'silent-smoke', level: 'proven', deletable: 'safe',\n reason: 'assertion-free test where every call is wrapped in a try{} with a silent catch — the test can never fail', stmtRef: null });\n } else if (!hasCalls) {\n rec.findings.push({ category: 'silent-smoke', level: 'proven', deletable: 'safe',\n reason: 'assertion-free test containing no calls — the test does nothing and can never fail', stmtRef: null });\n } else {\n rec.findings.push({ category: 'no-assert', level: 'advisory', deletable: 'report-only',\n reason: 'assertion-free smoke test — legitimate by design (it checks the code runs ' +\n \"without throwing). ICSE'19 distinguishes smoke tests from rotten tests; only worth a \" +\n 'look if an assertion was clearly intended here', stmtRef: null });\n }\n for (const f of rec.findings) allFindings.push(toReportFinding(projectDir, rec, f));\n testRecords.push(rec);\n return;\n }\n if (liveAsserts.length === 0) {\n // Every assertion is dead or swallowed, so the assertions can't fail the\n // test — but an UNGUARDED call still can, by throwing. Deleting the test\n // would drop that signal. A call inside a silently-caught try{} is not\n // such a signal (the catch absorbs the throw), so it doesn't count; nor\n // does the assertion machinery itself, nor console logging.\n const machinery = assertionMachineryNodes(ts, realAsserts);\n let remnant = false;\n walk(ts, body, n => {\n if (remnant) return;\n if (!ts.isCallExpression(n) && !ts.isNewExpression(n)) return;\n if (machinery.has(n) || silentlyGuarded.has(n)) return;\n if (isNoiseCall(ts, n.expression)) return;\n const top = topStatementOf(n);\n if (top && unreachableStmts.has(top)) return;\n remnant = true;\n });\n rec.findings.push(remnant\n ? { category: 'never-asserts', level: 'advisory', deletable: 'report-only', stmtRef: null,\n reason: 'every assertion is dead or swallowed, but an unguarded call remains that can ' +\n 'still fail this test by throwing — deleting it would drop that signal. Repair the ' +\n 'assertion, or delete by hand once you have confirmed the call cannot fail' }\n : { category: 'never-asserts', level: 'proven', deletable: 'safe', stmtRef: null,\n reason: 'every assertion in this test is unreachable or swallowed — the test can never fail' });\n for (const f of rec.findings) allFindings.push(toReportFinding(projectDir, rec, f));\n testRecords.push(rec);\n return;\n }\n\n const constMap = new Map();\n for (const s of statements) {\n if (ts.isVariableStatement(s) && (s.declarationList.flags & ts.NodeFlags.Const)) {\n for (const d of s.declarationList.declarations) {\n if (ts.isIdentifier(d.name) && d.initializer && isLiteralish(ts, d.initializer)) {\n constMap.set(d.name.text, literalValue(ts, d.initializer));\n }\n }\n }\n }\n\n const expectStmts = new Map();\n const topLevelExpectCalls = new Set();\n for (const s of statements) {\n if (!ts.isExpressionStatement(s)) continue;\n if (!ts.isAwaitExpression(s.expression)) {\n let probe = s.expression;\n let sawResolves = false;\n while (ts.isCallExpression(probe) || ts.isPropertyAccessExpression(probe)) {\n if (ts.isPropertyAccessExpression(probe) &&\n ['resolves', 'rejects'].includes(probe.name.text)) sawResolves = true;\n probe = probe.expression;\n }\n if (sawResolves && ts.isIdentifier(probe) && probe.text === 'expect') {\n const cline = sf.getLineAndCharacterOfPosition(s.getStart(sf)).line + 1;\n rec.findings.push({ category: 'floating-async-assert', level: 'advisory', deletable: 'report-only',\n reason: `async assertion at line ${cline} is not awaited — under Jest it silently never fails the test; ` +\n `bun:test and modern Vitest do catch it at settle time. Add await either way`, stmtRef: null });\n rec.nonRedundantExpects++;\n continue;\n }\n }\n const exp = parseExpectation(ts, s.expression);\n if (!exp) continue;\n if (unreachableStmts.has(s)) {\n rec.findings.push({ category: 'dead-assert', level: 'proven', deletable: 'safe', stmtRef: s,\n reason: 'sits after an unconditional return/throw — this assertion never executes' });\n continue;\n }\n expectStmts.set(s, exp);\n let e = s.expression;\n if (ts.isAwaitExpression(e)) e = e.expression;\n walk(ts, e, n => {\n if (ts.isCallExpression(n) && rootIdentifier(ts, n.expression) === 'expect') topLevelExpectCalls.add(n);\n });\n }\n\n for (const c of liveAsserts) {\n if (topLevelExpectCalls.has(c)) continue;\n let n = c.parent, crossed = null;\n while (n && n !== fn) {\n if (ts.isIfStatement(n) || ts.isIterationStatement?.(n, false) ||\n ts.isTryStatement(n) || ts.isCatchClause(n) ||\n ts.isArrowFunction(n) || ts.isFunctionExpression(n)) { crossed = n; break; }\n n = n.parent;\n }\n if (crossed) {\n rec.nestedAssertions++;\n if (ts.isIfStatement(crossed)) {\n const cline = sf.getLineAndCharacterOfPosition(c.getStart(sf)).line + 1;\n rec.findings.push({ category: 'conditional-assert', level: 'advisory', deletable: 'report-only',\n reason: `assertion at line ${cline} is gated behind an if — it may never execute (rotten green)`,\n covLine: cline, stmtRef: null });\n }\n }\n }\n\n const mockFindings = detectMockEcho(ts, statements, expectStmts);\n\n for (const [s, exp] of expectStmts) {\n rec.expectCount++;\n if (mockFindings.has(s)) {\n const f = { ...mockFindings.get(s), stmtRef: s };\n rec.findings.push(f);\n continue;\n }\n if (exp.unsupported) { rec.nonRedundantExpects++; continue; }\n exp.testTitle = rec.title;\n let verdict = classifyExpect(ts, checker, typesAvailable, strictNull, uncheckedIndex, exp, constMap);\n if (verdict && verdict.category === 'type-guaranteed' &&\n subjectLaunders(ts, checker, exp.subject, statements)) {\n verdict = null;\n }\n if (verdict) rec.findings.push({ ...verdict, stmtRef: s });\n else rec.nonRedundantExpects++;\n }\n\n // -- try-catch without fail (missed-fail)\n walk(ts, fn, n => {\n if (ts.isTryStatement(n) && n.catchClause) {\n let catchHasAssert = false;\n walk(ts, n.catchClause, m => {\n if (ts.isCallExpression(m)) {\n const root = rootIdentifier(ts, m.expression);\n if (root && isAssertionRoot(root) && isOutermostAssertCall(ts, m)) catchHasAssert = true;\n }\n });\n if (catchHasAssert) {\n let tryHasFail = false;\n walk(ts, n.tryBlock, m => {\n if (ts.isCallExpression(m)) {\n const root = rootIdentifier(ts, m.expression);\n if (root === 'fail') tryHasFail = true;\n } else if (ts.isThrowStatement(m)) {\n tryHasFail = true;\n }\n });\n if (!tryHasFail) {\n const cline = sf.getLineAndCharacterOfPosition(n.getStart(sf)).line + 1;\n rec.findings.push({ category: 'missed-fail', level: 'advisory', deletable: 'report-only',\n reason: `try block at line ${cline} catches an exception and asserts on it, but lacks a forced fail (e.g. fail()) at the end of the try block — if no exception is thrown, the test will pass silently`, stmtRef: null });\n }\n }\n }\n });\n\n // -- missed-skip (conditional early return/skip preceding assertions)\n const paramNames = new Set();\n for (const p of fn.parameters) {\n if (ts.isIdentifier(p.name)) paramNames.add(p.name.text);\n }\n for (let i = 0; i \u003c statements.length; i++) {\n const s = statements[i];\n if (ts.isIfStatement(s)) {\n let hasEarlyExit = false;\n walk(ts, s, x => {\n if (ts.isReturnStatement(x)) hasEarlyExit = true;\n else if (ts.isCallExpression(x)) {\n const root = rootIdentifier(ts, x.expression);\n if (root === 'skip') hasEarlyExit = true;\n }\n });\n if (hasEarlyExit) {\n let assertionsAfter = false;\n for (let j = i + 1; j \u003c statements.length; j++) {\n walk(ts, statements[j], x => {\n if (ts.isCallExpression(x)) {\n const root = rootIdentifier(ts, x.expression);\n if (root && isAssertionRoot(root) && isOutermostAssertCall(ts, x)) assertionsAfter = true;\n }\n });\n if (assertionsAfter) break;\n }\n if (assertionsAfter) {\n const condNames = new Set();\n walk(ts, s.expression, x => {\n if (ts.isIdentifier(x)) condNames.add(x.text);\n });\n let overlaps = false;\n for (const name of condNames) {\n if (paramNames.has(name)) overlaps = true;\n }\n if (!overlaps) {\n const cline = sf.getLineAndCharacterOfPosition(s.getStart(sf)).line + 1;\n rec.findings.push({ category: 'missed-skip', level: 'advisory', deletable: 'report-only',\n reason: `conditional early return/skip at line ${cline} precedes assertions — if the condition is met, the remaining assertions never run (a bare return passes silently; this.skip() at least reports a skip)`, stmtRef: null });\n }\n }\n }\n }\n }\n\n for (const f of rec.findings) allFindings.push(toReportFinding(projectDir, rec, f));\n testRecords.push(rec);\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":17742,"content_sha256":"6acc59188ab5b6c917a2b5e3ef55ded483ac73bb4f32c4ab45ff39a6cf1cd714"},{"filename":"scripts/co_ts/ast_utils.mjs","content":"export const norm = (s) => s.replace(/\\s+/g, '');\n\nexport function canon(ts, text) {\n const sc = ts.createScanner(ts.ScriptTarget.Latest, /*skipTrivia*/ true,\n ts.LanguageVariant.Standard, text);\n const toks = [];\n let k;\n try {\n while ((k = sc.scan()) !== ts.SyntaxKind.EndOfFileToken) {\n if (k === ts.SyntaxKind.Unknown) return norm(text);\n toks.push(sc.getTokenText());\n }\n } catch {\n return norm(text);\n }\n return toks.join(' ');\n}\n\nexport function nameTokens(title) {\n const words = (title || '').match(/[A-Z]?[a-z0-9]+|[A-Z]+(?![a-z])/g) || [];\n return new Set(words.map(w => w.toLowerCase()).filter(w => w && !/^\\d+$/.test(w)));\n}\n\nexport function namesDiverge(a, b) {\n const ta = nameTokens(a), tb = nameTokens(b);\n if (!ta.size || !tb.size) return false;\n let inter = 0;\n for (const w of ta) if (tb.has(w)) inter++;\n const union = ta.size + tb.size - inter;\n return inter / union \u003c 0.6;\n}\n\nexport function walk(ts, node, fn) {\n fn(node);\n ts.forEachChild(node, c => walk(ts, c, fn));\n}\n\nexport function hasUnsafeCast(ts, node) {\n let found = false;\n walk(ts, node, n => {\n if (found) return;\n if (ts.isAsExpression(n)) {\n const asConst = ts.isTypeReferenceNode(n.type) && n.type.typeName.getText() === 'const';\n if (!asConst) found = true;\n } else if (n.kind === ts.SyntaxKind.TypeAssertionExpression || ts.isNonNullExpression(n)) {\n found = true;\n }\n });\n return found;\n}\n\nexport function isSilentCatch(ts, catchClause) {\n return catchClause.block.statements.every(s =>\n ts.isExpressionStatement(s) && ts.isCallExpression(s.expression) &&\n rootIdentifier(ts, s.expression.expression) === 'console');\n}\n\n// The call nodes that make up the assertion itself — for `expect(x).toBe(1)`\n// that is the `.toBe(1)` call, the `expect(...)` call, and the property access\n// between them, but NOT the argument expressions. Callers use this to tell\n// assertion machinery apart from code the test genuinely exercises.\nexport function assertionMachineryNodes(ts, assertCalls) {\n const nodes = new Set();\n for (const c of assertCalls) {\n let n = c;\n while (n) {\n nodes.add(n);\n if (ts.isCallExpression(n) || ts.isPropertyAccessExpression(n)) n = n.expression;\n else break;\n }\n }\n return nodes;\n}\n\nexport function hasElementAccess(ts, node) {\n let found = false;\n walk(ts, node, n => { if (ts.isElementAccessExpression(n)) found = true; });\n return found;\n}\n\nexport function rootIdentifier(ts, expr) {\n let n = expr;\n while (true) {\n if (ts.isCallExpression(n) || ts.isPropertyAccessExpression(n) ||\n ts.isElementAccessExpression(n) || ts.isNonNullExpression(n)) { n = n.expression; continue; }\n if (ts.isAwaitExpression(n) || ts.isParenthesizedExpression(n)) { n = n.expression; continue; }\n return ts.isIdentifier(n) ? n.text : null;\n }\n}\n\nexport const isLiteralish = (ts, n) =>\n ts.isStringLiteralLike(n) || ts.isNumericLiteral(n) ||\n n.kind === ts.SyntaxKind.TrueKeyword || n.kind === ts.SyntaxKind.FalseKeyword ||\n n.kind === ts.SyntaxKind.NullKeyword ||\n (ts.isPrefixUnaryExpression(n) && n.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(n.operand)) ||\n (ts.isIdentifier(n) && n.text === 'undefined');\n\nexport const NO_VALUE = Symbol('no');\n\nexport function literalValue(ts, n) {\n if (ts.isStringLiteralLike(n)) return n.text;\n if (ts.isNumericLiteral(n)) return Number(n.text);\n if (n.kind === ts.SyntaxKind.TrueKeyword) return true;\n if (n.kind === ts.SyntaxKind.FalseKeyword) return false;\n if (n.kind === ts.SyntaxKind.NullKeyword) return null;\n if (ts.isIdentifier(n) && n.text === 'undefined') return undefined;\n if (ts.isPrefixUnaryExpression(n) && n.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(n.operand)) {\n return -Number(n.operand.text);\n }\n return NO_VALUE;\n}\n\nexport function isSimpleChain(ts, n) {\n if (ts.isIdentifier(n) || n.kind === ts.SyntaxKind.ThisKeyword) return true;\n if (ts.isPropertyAccessExpression(n)) return isSimpleChain(ts, n.expression);\n return false;\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":4067,"content_sha256":"6447fe187a4bfbfc8a3f149b1da78d59c28d54e38ac0bdc2a884a6d7f3a2210b"},{"filename":"scripts/co_ts/classifier.mjs","content":"import {\n isLiteralish,\n literalValue,\n isSimpleChain,\n canon,\n hasUnsafeCast,\n hasElementAccess,\n walk,\n NO_VALUE\n} from './ast_utils.mjs';\n\nimport {\n isBadType,\n typeExcludes,\n isAlwaysTruthy,\n isDeclaredPropertyAccess,\n instanceOfVerdict,\n isArrayType,\n TYPEOF_CHECKS,\n parts\n} from './type_predicates.mjs';\n\nimport { parseExpectHelper, EQ_MATCHERS } from './expect_parser.mjs';\n\nexport function classifyExpect(ts, checker, typesAvailable, strictNull, uncheckedIndex, exp, constMap = new Map()) {\n const { subject, matcher, args, negated } = exp;\n const arg0 = args[0];\n\n // ---- boundary-tautology: a .length/.size can never be negative\n if (!negated && ts.isPropertyAccessExpression(subject) &&\n ['length', 'size'].includes(subject.name.text) && arg0 && isLiteralish(ts, arg0)) {\n const v = literalValue(ts, arg0);\n if ((matcher === 'toBeGreaterThanOrEqual' && v === 0) ||\n (matcher === 'toBeGreaterThan' && v === -1)) {\n return { category: 'boundary-tautology', level: 'proven', deletable: 'safe',\n reason: `${subject.getText()} can never be negative — the comparison always holds` };\n }\n }\n\n // ---- local-const-echo: const x = LIT; ... expect(x).toBe(LIT)\n if (!negated && EQ_MATCHERS.has(matcher) && arg0 &&\n ts.isIdentifier(subject) && constMap.has(subject.text) && isLiteralish(ts, arg0)) {\n const bound = constMap.get(subject.text), asserted = literalValue(ts, arg0);\n if (bound !== NO_VALUE && asserted !== NO_VALUE && bound === asserted) {\n return { category: 'local-const-echo', level: 'proven', deletable: 'safe',\n reason: `${subject.text} is a const bound to ${JSON.stringify(bound)} two lines up — the test asserts its own arrangement` };\n }\n }\n\n // ---- self-compare-call: expect(f(a)).toEqual(f(a))\n // (literal subjects fall through to constant-assert below: expect(true)\n // .toBe(true) is a proven tautology, not a maybe-nondeterministic compare)\n if (!negated && EQ_MATCHERS.has(matcher) && arg0 && !isSimpleChain(ts, subject) &&\n !isLiteralish(ts, subject) &&\n canon(ts, subject.getText()) === canon(ts, arg0.getText()) &&\n !/stable|determin|consistent|idempotent|same|pure/i.test(exp.testTitle ?? '')) {\n return { category: 'self-compare-call', level: 'advisory', deletable: 'report-only',\n reason: `compares ${subject.getText().slice(0, 60)} to an identical expression — equal by construction unless nondeterministic` };\n }\n\n // ---- smoke-only: not.toThrow()\n if (negated && (matcher === 'toThrow' || matcher === 'toThrowError')) {\n return { category: 'smoke-only', level: 'advisory', deletable: 'report-only',\n reason: 'not.toThrow() adds nothing — calling the function directly fails the test on throw anyway; assert on the return value instead' };\n }\n\n // ---- constant-assert\n if (!negated && EQ_MATCHERS.has(matcher) && arg0) {\n if (isLiteralish(ts, subject) && isLiteralish(ts, arg0)) {\n const a = literalValue(ts, subject), b = literalValue(ts, arg0);\n if (a !== NO_VALUE && b !== NO_VALUE && a === b) {\n return { category: 'constant-assert', level: 'proven', deletable: 'safe',\n reason: `compares constant ${JSON.stringify(a)} to itself` };\n }\n return null;\n }\n if (isSimpleChain(ts, subject) && canon(ts, subject.getText()) === canon(ts, arg0.getText())) {\n return { category: 'constant-assert', level: 'proven', deletable: 'safe',\n reason: `compares ${subject.getText()} to itself` };\n }\n }\n if (!negated && matcher === 'toBeTruthy' && args.length === 0 && isLiteralish(ts, subject)) {\n const v = literalValue(ts, subject);\n if (v !== NO_VALUE && !!v) {\n return { category: 'constant-assert', level: 'proven', deletable: 'safe',\n reason: `literal ${JSON.stringify(v)} is always truthy` };\n }\n }\n\n if (!typesAvailable) return null;\n\n // ---- type-guaranteed family\n let subjectHasCall = false;\n if (subject) walk(ts, subject, (n) => {\n if (ts.isCallExpression(n) || ts.isNewExpression(n)) subjectHasCall = true;\n });\n const proven = (reason) => subjectHasCall\n ? { category: 'type-guaranteed', level: 'advisory', deletable: 'report-only',\n reason: reason + ' — subject inlines a call, kept advisory to preserve smoke coverage' }\n : { category: 'type-guaranteed', level: 'proven', deletable: 'safe', reason };\n const advisory = (reason) => ({ category: 'type-guaranteed', level: 'advisory', deletable: 'aggressive', reason });\n\n // negated typeof\n if (negated && ts.isTypeOfExpression(subject) && EQ_MATCHERS.has(matcher) &&\n arg0 && ts.isStringLiteralLike(arg0) && arg0.text === 'undefined' && strictNull) {\n const operand = subject.expression;\n if (!hasUnsafeCast(ts, operand)) {\n const t = checker.getTypeAtLocation(operand);\n if (!isBadType(ts, t) && typeExcludes(t, ts.TypeFlags.Undefined | ts.TypeFlags.Void) &&\n !(hasElementAccess(ts, operand) && !uncheckedIndex) && isDeclaredPropertyAccess(checker, operand)) {\n return proven(`type ${checker.typeToString(t)} already excludes undefined — typeof can never be \"undefined\"`);\n }\n }\n return null;\n }\n\n // typeof x / toBeTypeOf\n const typeofTarget =\n (!negated && ts.isTypeOfExpression(subject) && EQ_MATCHERS.has(matcher) &&\n arg0 && ts.isStringLiteralLike(arg0)) ? { operand: subject.expression, name: arg0.text }\n : (!negated && matcher === 'toBeTypeOf' && arg0 && ts.isStringLiteralLike(arg0))\n ? { operand: subject, name: arg0.text } : null;\n if (typeofTarget) {\n const check = TYPEOF_CHECKS(ts)[typeofTarget.name];\n if (!check || hasUnsafeCast(ts, typeofTarget.operand)) return null;\n const t = checker.getTypeAtLocation(typeofTarget.operand);\n if (!isBadType(ts, t) && parts(t).every(check)) {\n return proven(`compiler already guarantees typeof is \"${typeofTarget.name}\" (type: ${checker.typeToString(t)})`);\n }\n return null;\n }\n\n if (hasUnsafeCast(ts, subject)) return null;\n const t = () => checker.getTypeAtLocation(subject);\n\n // toBeDefined / not.toBeUndefined / not.toBeNull / toBeNull / toBeUndefined\n if ((matcher === 'toBeDefined' && !negated) || (matcher === 'toBeUndefined' && negated)) {\n if (!strictNull) return null;\n const ty = t();\n if (!isBadType(ts, ty) && typeExcludes(ty, ts.TypeFlags.Undefined | ts.TypeFlags.Void)) {\n if (hasElementAccess(ts, subject) && !uncheckedIndex) {\n return advisory(`type ${checker.typeToString(ty)} excludes undefined, but indexed access without noUncheckedIndexedAccess can lie`);\n }\n if (!isDeclaredPropertyAccess(checker, subject)) {\n return advisory(`type ${checker.typeToString(ty)} excludes undefined, but the property comes from an index signature — the type is a promise, not a check`);\n }\n return proven(`type ${checker.typeToString(ty)} already excludes undefined`);\n }\n return null;\n }\n if (matcher === 'toBeNull' && negated) {\n if (!strictNull) return null;\n const ty = t();\n if (!isBadType(ts, ty) && typeExcludes(ty, ts.TypeFlags.Null)) {\n return proven(`type ${checker.typeToString(ty)} already excludes null`);\n }\n return null;\n }\n\n // toBeTruthy / not.toBeFalsy\n if ((matcher === 'toBeTruthy' && !negated) || (matcher === 'toBeFalsy' && negated)) {\n if (!strictNull) return null;\n const ty = t();\n if (!isBadType(ts, ty) && isAlwaysTruthy(ts, checker, ty)) {\n if ((hasElementAccess(ts, subject) && !uncheckedIndex) || !isDeclaredPropertyAccess(checker, subject)) {\n return advisory(`type ${checker.typeToString(ty)} is always truthy, but the value comes through an index signature or unchecked indexed access — the type may lie`);\n }\n return proven(`type ${checker.typeToString(ty)} is always truthy`);\n }\n return null;\n }\n\n // toBeInstanceOf\n if (matcher === 'toBeInstanceOf' && !negated && arg0) {\n const v = instanceOfVerdict(ts, checker, subject, arg0);\n return v ? { category: 'type-guaranteed', level: v.level,\n deletable: v.level === 'proven' ? 'safe' : 'aggressive', reason: v.reason } : null;\n }\n\n // expect(Array.isArray(x)).toBe(true) / toBeTruthy\n if (!negated && ts.isCallExpression(subject) && ts.isPropertyAccessExpression(subject.expression) &&\n subject.expression.name.text === 'isArray' &&\n ts.isIdentifier(subject.expression.expression) && subject.expression.expression.text === 'Array' &&\n subject.arguments.length === 1 &&\n ((EQ_MATCHERS.has(matcher) && arg0?.kind === ts.SyntaxKind.TrueKeyword) ||\n (matcher === 'toBeTruthy' && args.length === 0))) {\n const inner = subject.arguments[0];\n if (hasUnsafeCast(ts, inner)) return null;\n const ty = checker.getTypeAtLocation(inner);\n if (!isBadType(ts, ty) && parts(ty).every(p => isArrayType(checker, p))) {\n return proven(`type ${checker.typeToString(ty)} is already an array`);\n }\n return null;\n }\n\n // toEqual(expect.anything()) / toEqual(expect.any(Ctor))\n if (!negated && EQ_MATCHERS.has(matcher) && arg0) {\n const helper = parseExpectHelper(ts, arg0);\n if (helper?.kind === 'anything') {\n if (!strictNull) return null;\n const ty = t();\n if (!isBadType(ts, ty) && typeExcludes(ty, ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.Void)) {\n return proven(`expect.anything() matches everything non-null; type ${checker.typeToString(ty)} is never null/undefined`);\n }\n return null;\n }\n if (helper?.kind === 'any' && ts.isIdentifier(helper.ctor)) {\n const ctorName = helper.ctor.text;\n const prim = { Number: 'number', String: 'string', Boolean: 'boolean', Function: 'function', BigInt: 'bigint', Symbol: 'symbol' }[ctorName];\n const ty = t();\n if (prim) {\n if (!isBadType(ts, ty) && parts(ty).every(TYPEOF_CHECKS(ts)[prim])) {\n return proven(`expect.any(${ctorName}) matches any ${prim}; type is ${checker.typeToString(ty)}`);\n }\n return null;\n }\n if (ctorName === 'Object') {\n if (!isBadType(ts, ty) && parts(ty).every(p => p.flags & ts.TypeFlags.Object)) {\n return proven(`expect.any(Object) matches any object; type is ${checker.typeToString(ty)}`);\n }\n return null;\n }\n const v = instanceOfVerdict(ts, checker, subject, helper.ctor);\n return v ? { category: 'type-guaranteed', level: v.level,\n deletable: v.level === 'proven' ? 'safe' : 'aggressive',\n reason: `expect.any = instanceof check; ${v.reason}` } : null;\n }\n }\n\n // toHaveProperty('name')\n if (!negated && matcher === 'toHaveProperty' && args.length === 1 && arg0 && ts.isStringLiteralLike(arg0) &&\n !arg0.text.includes('.')) {\n const ty = t();\n if (isBadType(ts, ty)) return null;\n const ok = parts(ty).every(p => {\n if (p.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) return false;\n const prop = checker.getPropertyOfType(p, arg0.text);\n return prop && !(prop.flags & ts.SymbolFlags.Optional);\n });\n if (ok) return proven(`property \"${arg0.text}\" is required on type ${checker.typeToString(t())}`);\n return null;\n }\n\n return null;\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":11268,"content_sha256":"9314befc8e35e003e2125725470b5ac4017f71bdeb55561b65884fccfd019636"},{"filename":"scripts/co_ts/coverage.mjs","content":"import fs from 'node:fs';\nimport path from 'node:path';\n\nexport function loadCoverage(file, projectDir) {\n let raw;\n try { raw = fs.readFileSync(file, 'utf8'); } catch { return null; }\n const map = new Map();\n const norm = (p) => path.relative(projectDir, path.isAbsolute(p) ? p : path.resolve(projectDir, p))\n .split(path.sep).join('/');\n const put = (p, line, hits) => {\n const rel = norm(p);\n let m = map.get(rel);\n if (!m) { m = new Map(); map.set(rel, m); }\n m.set(line, Math.max(m.get(line) ?? 0, hits));\n };\n const trimmed = raw.trimStart();\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n let json;\n try { json = JSON.parse(raw); } catch { return null; }\n if (json && json.files && typeof json.files === 'object') {\n for (const [p, d] of Object.entries(json.files)) {\n for (const ln of d.executed_lines ?? []) put(p, ln, 1);\n for (const ln of d.missing_lines ?? []) put(p, ln, 0);\n }\n } else if (json && typeof json === 'object') {\n for (const [p, d] of Object.entries(json)) {\n if (!d || !d.statementMap || !d.s) continue;\n for (const [id, loc] of Object.entries(d.statementMap)) {\n const line = loc?.start?.line;\n if (line == null) continue;\n put(d.path ?? p, line, d.s[id] ?? 0);\n }\n }\n }\n } else {\n let cur = null;\n for (const line of raw.split(/\\r?\\n/)) {\n if (line.startsWith('SF:')) cur = line.slice(3).trim();\n else if (line.startsWith('DA:') && cur) {\n const [ln, hits] = line.slice(3).split(',');\n put(cur, parseInt(ln, 10), parseInt(hits, 10) || 0);\n } else if (line.startsWith('end_of_record')) cur = null;\n }\n }\n if (map.size === 0) return null;\n return {\n hits(relFile, line) {\n const m = map.get(String(relFile).split(path.sep).join('/'));\n if (!m) return undefined;\n return m.has(line) ? m.get(line) : undefined;\n },\n hasFile(relFile) {\n return map.has(String(relFile).split(path.sep).join('/'));\n },\n };\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":2038,"content_sha256":"a63643e0541ba203aa3bc05e9768a6c4c600685bd33e69acad3180b87505f16c"},{"filename":"scripts/co_ts/discovery.mjs","content":"import fs from 'node:fs';\nimport path from 'node:path';\n\nexport const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'out', 'coverage', '.next', '.turbo']);\nexport const TEST_RE = /\\.(test|spec)\\.(ts|tsx|mts|cts|js|jsx|mjs|cjs)$/;\n\nexport function findTestFiles(root) {\n const found = [];\n (function walk(dir) {\n let entries;\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }\n for (const e of entries) {\n if (e.isDirectory()) {\n if (!SKIP_DIRS.has(e.name) && !e.name.startsWith('.')) walk(path.join(dir, e.name));\n } else if (TEST_RE.test(e.name) ||\n (/\\.(ts|tsx|js|jsx)$/.test(e.name) && path.basename(dir) === '__tests__')) {\n found.push(path.join(dir, e.name));\n }\n }\n })(root);\n return found.sort();\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":815,"content_sha256":"051eed0927fa8a137916d87319d66501f27ea3912d54e4082052cece6be046c0"},{"filename":"scripts/co_ts/duplicates.mjs","content":"import { canon, namesDiverge } from './ast_utils.mjs';\nimport { toReportFinding, enclosingDescribeKey } from './analyzer.mjs';\n\nexport function markDuplicates(ts, printer, testRecords, allFindings, projectDir) {\n const seen = new Map();\n const seenGlobal = new Map();\n for (const rec of testRecords) {\n const bodyText = ts.isBlock(rec.fn.body)\n ? printer.printNode(ts.EmitHint.Unspecified, rec.fn.body, rec.sf)\n : rec.fn.body.getText(rec.sf);\n // snapshot/baseline tests have identical bodies by design — each is keyed\n // to a distinct stored baseline by test name, so deleting one orphans it\n if (/Match\\w*Snapshot/.test(bodyText)) continue;\n const bodyKey = canon(ts, bodyText);\n if (bodyKey.length \u003c 8) continue;\n const key = enclosingDescribeKey(ts, rec.stmt, rec.sf) + '::' + bodyKey;\n if (seen.has(key)) {\n const first = seen.get(key);\n let reason = `body is identical to \"${first.title}\" (line ${first.line}) in the same suite`;\n if (namesDiverge(rec.title, first.title)) {\n reason += \" — names differ, so this is likely a copy-paste that leaves this test's \" +\n 'named behaviour untested; deleting is coverage-safe but consider fixing the body instead';\n }\n const f = { category: 'duplicate-test', level: 'proven', deletable: 'safe',\n reason, stmtRef: null };\n rec.findings.push(f);\n rec.isDuplicate = true;\n allFindings.push(toReportFinding(projectDir, rec, f));\n } else {\n seen.set(key, rec);\n }\n\n const gkey = bodyKey;\n if (seenGlobal.has(gkey)) {\n const first = seenGlobal.get(gkey);\n const sameScope = first.sf.fileName === rec.sf.fileName &&\n enclosingDescribeKey(ts, first.stmt, first.sf) === enclosingDescribeKey(ts, rec.stmt, rec.sf);\n if (!rec.isDuplicate && !sameScope) {\n const where = `${first.sf.fileName.split('/').pop()}:${first.line}`;\n const f = { category: 'duplicate-test', level: 'advisory', deletable: 'report-only',\n reason: `body is identical to \"${first.title}\" (${where}) in a different suite — ` +\n 'likely redundant, but beforeEach/setup may differ, so review before removing', stmtRef: null };\n rec.findings.push(f);\n allFindings.push(toReportFinding(projectDir, rec, f));\n }\n } else {\n seenGlobal.set(gkey, rec);\n }\n }\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":2370,"content_sha256":"4a642a0faf89a8907a211028f823618f91db8dfd987a9653e5349e87afe1fd97"},{"filename":"scripts/co_ts/expect_parser.mjs","content":"import { rootIdentifier } from './ast_utils.mjs';\n\nexport function parseExpectation(ts, expr) {\n let call = expr;\n if (ts.isAwaitExpression(call)) call = call.expression;\n if (!ts.isCallExpression(call) || !ts.isPropertyAccessExpression(call.expression)) return null;\n const matcher = call.expression.name.text;\n let base = call.expression.expression;\n let negated = false;\n if (ts.isPropertyAccessExpression(base) && base.name.text === 'not') { negated = true; base = base.expression; }\n if (ts.isPropertyAccessExpression(base) && ['resolves', 'rejects'].includes(base.name.text)) return { unsupported: true };\n if (!ts.isCallExpression(base)) return null;\n const be = base.expression;\n const isExpect = (ts.isIdentifier(be) && be.text === 'expect') ||\n (ts.isPropertyAccessExpression(be) && ts.isIdentifier(be.expression) &&\n be.expression.text === 'expect' && be.name.text === 'soft');\n if (!isExpect || base.arguments.length !== 1) return null;\n return { subject: base.arguments[0], matcher, args: [...call.arguments], negated };\n}\n\nexport function parseExpectHelper(ts, arg) {\n if (!ts.isCallExpression(arg) || !ts.isPropertyAccessExpression(arg.expression)) return null;\n const pa = arg.expression;\n if (!ts.isIdentifier(pa.expression) || pa.expression.text !== 'expect') return null;\n if (pa.name.text === 'anything') return { kind: 'anything' };\n if (pa.name.text === 'any' && arg.arguments.length === 1) return { kind: 'any', ctor: arg.arguments[0] };\n return null;\n}\nexport const EQ_MATCHERS = new Set(['toBe', 'toEqual', 'toStrictEqual']);\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":1577,"content_sha256":"dbb1307517114a35e66d6b87eebee42d1b375ee987995ec75659bb6514b2b4d1"},{"filename":"scripts/co_ts/fixer.mjs","content":"import path from 'node:path';\nimport { walk } from './ast_utils.mjs';\n\nexport function decideRemovals(ts, testRecords, doFix, report, fs, projectDir) {\n const removableTests = [];\n const removableStmts = [];\n\n for (const rec of testRecords) {\n // never plan a removal in a symlinked test file — the write would follow\n // the link out of the scanned tree. Excluding it here (not just at the\n // write) keeps report.fixed counts and report.plan honest about what --fix\n // will actually touch.\n if (fs.lstatSync(rec.sf.fileName).isSymbolicLink()) {\n console.error(`captain-obvious: skipping ${rec.sf.fileName} — symlinked test files are never rewritten (the write would follow the link)`);\n continue;\n }\n const wants = (f) => f.deletable === 'safe';\n\n if (rec.isDuplicate && wants(rec.findings.find(f => f.category === 'duplicate-test'))) {\n removableTests.push(rec);\n continue;\n }\n const never = rec.findings.find(f => ['never-asserts', 'silent-smoke'].includes(f.category));\n if (never) {\n if (wants(never)) removableTests.push(rec);\n continue;\n }\n // no-assert / skipped-test are never deletable:'safe' — whole-test\n // removal for them is the agent's call, not the fixer's\n if (rec.findings.some(f => ['no-assert', 'skipped-test'].includes(f.category))) continue;\n\n const stmtFindings = rec.findings.filter(f => f.stmtRef);\n const deadStmts = stmtFindings.filter(f => f.category === 'dead-assert');\n const liveDeletable = stmtFindings.filter(f => f.category !== 'dead-assert').filter(wants);\n const allRedundant =\n rec.expectCount > 0 &&\n liveDeletable.length === rec.expectCount &&\n rec.nonRedundantExpects === 0 &&\n rec.nestedAssertions === 0;\n\n let remainingCall = false;\n if (allRedundant && ts.isBlock(rec.fn.body)) {\n const del = new Set(liveDeletable.map(f => f.stmtRef));\n for (const st of rec.fn.body.statements) {\n if (del.has(st)) continue;\n if (ts.isExpressionStatement(st) && ts.isStringLiteral(st.expression)) continue;\n walk(ts, st, n => {\n if (ts.isCallExpression(n) || ts.isNewExpression(n)) remainingCall = true;\n });\n if (remainingCall) break;\n }\n }\n const wholeTest = allRedundant && !remainingCall;\n\n if (wholeTest) removableTests.push(rec);\n else {\n const remainingAsserts = rec.nonRedundantExpects + rec.nestedAssertions +\n stmtFindings.filter(f => f.deletable === 'report-only').length;\n if (liveDeletable.length > 0 && remainingAsserts > 0 && !rec.hasAssertionCtl) {\n removableStmts.push(...liveDeletable.map(f => ({ rec, stmt: f.stmtRef })));\n }\n removableStmts.push(...deadStmts.map(f => ({ rec, stmt: f.stmtRef })));\n }\n }\n\n report.plan = {\n testsToRemove: removableTests.map(r => ({ file: path.relative(projectDir, r.sf.fileName), line: r.line, test: r.title })),\n assertionsToRemove: removableStmts.length,\n };\n\n if (doFix) {\n const editsByFile = new Map();\n const removedTestPos = new Set();\n for (const rec of removableTests) {\n const arr = editsByFile.get(rec.sf.fileName) ?? [];\n arr.push({ start: rec.stmt.getFullStart(), end: rec.stmt.getEnd() });\n removedTestPos.add(rec.stmt);\n editsByFile.set(rec.sf.fileName, arr);\n }\n for (const { rec, stmt } of removableStmts) {\n if (removedTestPos.has(rec.stmt)) continue;\n const arr = editsByFile.get(rec.sf.fileName) ?? [];\n arr.push({ start: stmt.getFullStart(), end: stmt.getEnd() });\n editsByFile.set(rec.sf.fileName, arr);\n }\n let filesChanged = 0;\n for (const [file, edits] of editsByFile) {\n let text = fs.readFileSync(file, 'utf8');\n edits.sort((a, b) => b.start - a.start);\n for (const e of edits) text = text.slice(0, e.start) + text.slice(e.end);\n fs.writeFileSync(file, text);\n filesChanged++;\n }\n report.fixed = { testsRemoved: removableTests.length, assertionsRemoved: removableStmts.length, filesChanged };\n }\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":4044,"content_sha256":"0deb52eaeb7c6b86b05f32bb9acfb807931c56a91ef8579c6e7305babd4ce28b"},{"filename":"scripts/co_ts/gitguard.mjs","content":"import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs';\n\n/**\n * Why --fix should not run here, or null if it's safe.\n *\n * --fix rewrites test files in place with no backup, so the undo path is\n * `git checkout -- \u003cfiles>`. That only exists if the target is a git repo and\n * the tests aren't already carrying uncommitted edits. Untracked files are\n * fine — they can't be clobbered by an in-place rewrite.\n */\nexport function fixBlocker(projectDir) {\n if (!fs.existsSync(projectDir) || !fs.statSync(projectDir).isDirectory())\n return `${projectDir} is not an existing directory`;\n\n const git = (args) =>\n spawnSync('git', args, { cwd: projectDir, encoding: 'utf8', timeout: 60000 });\n\n const inside = git(['rev-parse', '--is-inside-work-tree']);\n if (inside.error) return 'git is not available, so there is no undo path';\n if (inside.status !== 0 || inside.stdout.trim() !== 'true')\n return 'not a git repository, so there is no undo path';\n\n const status = git(['status', '--porcelain', '--untracked-files=no']);\n if (status.status !== 0)\n return 'could not read git status, so the undo path is unverified';\n const dirty = status.stdout.trim();\n if (dirty)\n return `the working tree has ${dirty.split('\\n').length} uncommitted change(s)`;\n return null;\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":1302,"content_sha256":"a7f3298f3866188a275e747b6125c7b7e703d3a305e64005a771f712d69be68a"},{"filename":"scripts/co_ts/laundering.mjs","content":"import { walk, hasUnsafeCast } from './ast_utils.mjs';\nimport { resolveSymbol } from './type_predicates.mjs';\n\nexport function callLaunders(ts, checker, callExpr, seen = new Set(), depth = 0) {\n if (depth > 5) return true; // deep chain: refuse to prove — stay safe\n let sym = checker.getSymbolAtLocation(callExpr.expression);\n sym = resolveSymbol(ts, checker, sym);\n const decl = (sym?.declarations ?? []).find(d =>\n (ts.isFunctionDeclaration(d) || ts.isMethodDeclaration(d) || ts.isArrowFunction(d) ||\n ts.isFunctionExpression(d)) && d.body) ??\n (sym?.valueDeclaration && ts.isVariableDeclaration(sym.valueDeclaration) &&\n sym.valueDeclaration.initializer &&\n (ts.isArrowFunction(sym.valueDeclaration.initializer) ||\n ts.isFunctionExpression(sym.valueDeclaration.initializer))\n ? sym.valueDeclaration.initializer : null);\n if (!decl || !decl.body || !decl.type) return false;\n if (seen.has(decl)) return false; // cycle: no new information\n seen.add(decl);\n let launders = false;\n walk(ts, decl.body, n => {\n if (launders) return;\n if (ts.isReturnStatement(n) && n.expression) {\n const t = checker.getTypeAtLocation(n.expression);\n if ((t.flags & ts.TypeFlags.Any) || hasUnsafeCast(ts, n.expression)) { launders = true; return; }\n let re = n.expression;\n while (ts.isAwaitExpression(re) || ts.isParenthesizedExpression(re)) re = re.expression;\n if (ts.isCallExpression(re) && callLaunders(ts, checker, re, seen, depth + 1)) launders = true;\n }\n });\n return launders;\n}\n\nexport function subjectLaunders(ts, checker, subject, statements) {\n const calls = [];\n walk(ts, subject, n => { if (ts.isCallExpression(n)) calls.push(n); });\n const names = new Set();\n walk(ts, subject, n => { if (ts.isIdentifier(n)) names.add(n.text); });\n for (const s of statements) {\n if (!ts.isVariableStatement(s)) continue;\n for (const d of s.declarationList.declarations) {\n if (ts.isIdentifier(d.name) && names.has(d.name.text) && d.initializer) {\n walk(ts, d.initializer, n => { if (ts.isCallExpression(n)) calls.push(n); });\n }\n }\n }\n return calls.some(c => callLaunders(ts, checker, c));\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":2200,"content_sha256":"cdd59a536c3f7ec79deca9f06a937cd4bdd95cd24582e3565e4123cab39bf1d3"},{"filename":"scripts/co_ts/mock_echo.mjs","content":"import { rootIdentifier, canon } from './ast_utils.mjs';\nimport { EQ_MATCHERS } from './expect_parser.mjs';\n\nexport function detectMockEcho(ts, statements, expectStmts) {\n const stubs = new Map();\n const directCalls = new Map();\n const bindings = new Map();\n const findings = new Map();\n\n for (const stmt of statements) {\n let e = ts.isExpressionStatement(stmt) ? stmt.expression : null;\n if (ts.isVariableStatement(stmt)) {\n for (const d of stmt.declarationList.declarations) {\n if (d.initializer && ts.isIdentifier(d.name)) {\n let init = d.initializer;\n if (ts.isAwaitExpression(init)) init = init.expression;\n if (ts.isCallExpression(init) && ts.isIdentifier(init.expression)) {\n bindings.set(d.name.text, { mock: init.expression.text });\n }\n }\n }\n continue;\n }\n if (!e) continue;\n if (ts.isAwaitExpression(e)) e = e.expression;\n\n if (ts.isCallExpression(e) && ts.isPropertyAccessExpression(e.expression) &&\n /^mock(Return|Resolved)Value(Once)?$/.test(e.expression.name.text) &&\n e.arguments.length === 1) {\n const root = rootIdentifier(ts, e.expression.expression);\n if (root) stubs.set(root, canon(ts, e.arguments[0].getText()));\n continue;\n }\n\n if (ts.isCallExpression(e) && ts.isIdentifier(e.expression)) {\n directCalls.set(e.expression.text, canon(ts, e.arguments.map(a => a.getText()).join(',')));\n continue;\n }\n\n const exp = expectStmts.get(stmt);\n if (!exp || exp.unsupported) continue;\n const { subject, matcher, args, negated } = exp;\n if (negated) continue;\n\n if (/^toHaveBeenCalled(Times|With)?$/.test(matcher)) {\n const root = rootIdentifier(ts, subject);\n if (root && directCalls.has(root)) {\n let ok = matcher !== 'toHaveBeenCalledWith' ||\n canon(ts, args.map(a => a.getText()).join(',')) === directCalls.get(root);\n if (matcher === 'toHaveBeenCalledTimes') ok = args[0]?.getText() === '1';\n if (ok) {\n findings.set(stmt, { category: 'mock-echo', level: 'proven', deletable: 'safe',\n reason: `test calls ${root}() itself, then asserts it was called — asserts the test's own action` });\n continue;\n }\n }\n }\n\n if (EQ_MATCHERS.has(matcher) && args[0]) {\n let root = null;\n let s = subject;\n if (ts.isAwaitExpression(s)) s = s.expression;\n if (ts.isCallExpression(s) && ts.isIdentifier(s.expression)) root = s.expression.text;\n else if (ts.isIdentifier(s) && bindings.get(s.text)) root = bindings.get(s.text).mock;\n if (root && stubs.has(root) && stubs.get(root) === canon(ts, args[0].getText())) {\n findings.set(stmt, { category: 'mock-echo', level: 'proven', deletable: 'safe',\n reason: `asserts ${root}() returns the exact value it was stubbed with — tests the mocking library` });\n }\n }\n }\n return findings;\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":2944,"content_sha256":"340057580a3b5d9c0ffa9e44c7cde2a6eaf69d5c521757a158a0d1c2fcd0c3d5"},{"filename":"scripts/co_ts/type_predicates.mjs","content":"import { hasUnsafeCast } from './ast_utils.mjs';\n\nexport const TYPEOF_CHECKS = (ts) => {\n const TF = ts.TypeFlags;\n return {\n string: t => !!(t.flags & TF.StringLike),\n number: t => !!(t.flags & TF.NumberLike),\n boolean: t => !!(t.flags & TF.BooleanLike),\n bigint: t => !!(t.flags & TF.BigIntLike),\n symbol: t => !!(t.flags & TF.ESSymbolLike),\n undefined: t => !!(t.flags & TF.Undefined),\n function: t => !!(t.flags & TF.Object) &&\n (t.getCallSignatures().length > 0 || t.getConstructSignatures().length > 0),\n };\n};\n\nexport const parts = (t) => (t.isUnion?.() ? t.types : [t]);\n\nexport function isBadType(ts, t) {\n const TF = ts.TypeFlags;\n const BAD_MASK = TF.Any | TF.Unknown | (TF.TypeVariable ?? 0) | (TF.Index ?? 0) |\n (TF.Conditional ?? 0) | (TF.Substitution ?? 0);\n return t.isIntersection?.() || parts(t).some(p => p.isIntersection?.() || (p.flags & BAD_MASK));\n}\n\nexport function typeExcludes(type, flags) {\n return !parts(type).some(p => p.flags & flags);\n}\n\nexport function isAlwaysTruthy(ts, checker, type) {\n const TF = ts.TypeFlags;\n return parts(type).every(p => {\n if (p.flags & (TF.Null | TF.Undefined | TF.Void)) return false;\n if (p.isStringLiteral?.()) return p.value !== '';\n if (p.isNumberLiteral?.()) return p.value !== 0 && !Number.isNaN(p.value);\n if (p.flags & TF.BooleanLiteral) return checker.typeToString(p) === 'true';\n if (p.flags & TF.Object) return true;\n return false;\n });\n}\n\nexport function resolveSymbol(ts, checker, sym) {\n if (sym && (sym.flags & ts.SymbolFlags.Alias)) {\n try { return checker.getAliasedSymbol(sym); } catch { return sym; }\n }\n return sym;\n}\n\nexport function classDeclOf(ts, sym) {\n if (!sym) return null;\n if (sym.valueDeclaration && ts.isClassLike(sym.valueDeclaration)) return sym.valueDeclaration;\n return (sym.declarations ?? []).find(d => ts.isClassLike(d)) ?? null;\n}\n\nexport function classChainIncludes(ts, checker, startSym, targetSym) {\n let sym = resolveSymbol(ts, checker, startSym), guard = 0;\n while (sym && guard++ \u003c 50) {\n if (sym === targetSym) return true;\n const decl = classDeclOf(ts, sym);\n if (!decl) return false;\n const ext = (decl.heritageClauses ?? []).find(h => h.token === ts.SyntaxKind.ExtendsKeyword);\n if (!ext || !ext.types[0]) return false;\n sym = resolveSymbol(ts, checker, checker.getTypeAtLocation(ext.types[0].expression)?.getSymbol());\n }\n return false;\n}\n\nexport function chainHasPrivateMember(ts, checker, startSym) {\n let sym = resolveSymbol(ts, checker, startSym), guard = 0;\n while (sym && guard++ \u003c 50) {\n const decl = classDeclOf(ts, sym);\n if (!decl) return false;\n for (const m of decl.members ?? []) {\n if (m.name && ts.isPrivateIdentifier(m.name)) return true;\n const mods = ts.canHaveModifiers?.(m) ? ts.getModifiers(m) ?? [] : (m.modifiers ?? []);\n if (mods.some(x => x.kind === ts.SyntaxKind.PrivateKeyword || x.kind === ts.SyntaxKind.ProtectedKeyword)) return true;\n }\n const ext = (decl.heritageClauses ?? []).find(h => h.token === ts.SyntaxKind.ExtendsKeyword);\n if (!ext || !ext.types[0]) return false;\n sym = resolveSymbol(ts, checker, checker.getTypeAtLocation(ext.types[0].expression)?.getSymbol());\n }\n return false;\n}\n\nexport function isDeclaredPropertyAccess(checker, subject) {\n if (!subject || !subject.expression || !subject.name) return true;\n const objType = checker.getTypeAtLocation(subject.expression);\n return parts(objType).every(p => checker.getPropertyOfType(p, subject.name.text));\n}\n\nexport function instanceOfVerdict(ts, checker, subject, classArg) {\n const t = checker.getTypeAtLocation(subject);\n if (isBadType(ts, t) || hasUnsafeCast(ts, subject)) return null;\n const classSym = resolveSymbol(ts, checker, checker.getSymbolAtLocation(classArg));\n if (!classDeclOf(ts, classSym)) return null;\n for (const p of parts(t)) {\n if (p.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) return null;\n if (!classChainIncludes(ts, checker, p.getSymbol?.(), classSym)) return null;\n }\n const nominal = parts(t).every(p => chainHasPrivateMember(ts, checker, p.getSymbol?.()));\n return nominal\n ? { level: 'proven', reason: `type is ${checker.typeToString(t)} (nominal — has private members), instanceof cannot fail` }\n : { level: 'advisory', reason: `declared type is ${checker.typeToString(t)}, but TS is structural — a shaped non-instance could sneak in` };\n}\n\nexport function isArrayType(checker, t) {\n if (typeof checker.isArrayLikeType === 'function') return checker.isArrayLikeType(t);\n const s = checker.typeToString(t);\n return /\\[\\]$/.test(s) || /^(Readonly)?Array\u003c/.test(s) || /^readonly .*\\[\\]$/.test(s);\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":4723,"content_sha256":"973ff48e698c602e2b5d492cbd2137f2402a678dd2bb4a0bb9e9f8cdbd202c04"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Captain Obvious","type":"text"}]},{"type":"paragraph","content":[{"text":"Deletes tests that assert what is already guaranteed — by the compiler, by the mock framework, or by the laws of logic. These tests burn CI time, inflate coverage confidence, and can never catch a regression. They are the signature of AI-generated test suites (empirical studies find test smells in 38–100% of LLM-generated tests).","type":"text"}]},{"type":"paragraph","content":[{"text":"For cleanup, two deterministic scripts in ","type":"text"},{"text":"scripts/","type":"text","marks":[{"type":"code_inline"}]},{"text":" do the heavy lifting. Run them, interpret the report, clean up the residue, and verify nothing broke. ","type":"text"},{"text":"Do not","type":"text","marks":[{"type":"strong"}]},{"text":" hand-scan test files or spawn subagents per file — one script invocation scans the whole project. During test authoring, use the gate below without running a cleanup scan.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Authoring gate","type":"text"}]},{"type":"paragraph","content":[{"text":"Before adding or changing a test, answer four questions:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"What observable behavior or independent contract does it protect?","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"What plausible regression would make it fail for the intended reason?","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Is that contract already covered at a stronger boundary? If so, what distinct risk does this test cover?","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Does it require a production export, flag, wrapper, or injection hook used only by tests? Can the real entry point be tested instead?","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"If a new bug regression test can be run safely against the pre-fix baseline, verify that it fails for the intended reason and passes with the fix. Use ","type":"text"},{"text":"references/prevention.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" for examples of patterns to avoid. A test need not contain a direct assertion to be valuable: a deliberate must-not-raise test can guard a real contract.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflow","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. Detect the stack(s)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"TypeScript/JavaScript: ","type":"text"},{"text":"*.test.*","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"*.spec.*","type":"text","marks":[{"type":"code_inline"}]},{"text":" (ts, tsx, mts, cts, js, jsx, mjs, cjs) or files under ","type":"text"},{"text":"__tests__","type":"text","marks":[{"type":"code_inline"}]},{"text":"; a ","type":"text"},{"text":"tsconfig.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" enables type checks.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Python: ","type":"text"},{"text":"test_*.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"*_test.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" files (pytest or unittest).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"A repo can have both; run both detectors.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. Safety first","type":"text"}]},{"type":"paragraph","content":[{"text":"The fix step edits test files in place. Both scripts enforce this themselves: ","type":"text"},{"text":"--fix","type":"text","marks":[{"type":"code_inline"}]},{"text":" exits 2 unless the target is a git repository with a clean working tree (untracked files are fine). If it refuses, stash or commit rather than reaching for ","type":"text"},{"text":"--force","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"--force","type":"text","marks":[{"type":"code_inline"}]},{"text":" removes the only undo path there is (","type":"text"},{"text":"git checkout -- \u003cfiles>","type":"text","marks":[{"type":"code_inline"}]},{"text":"), so use it only when the user has explicitly accepted that.","type":"text"}]},{"type":"paragraph","content":[{"text":"Trust boundary: scanning executes the project's own toolchain. mypy loads ","type":"text"},{"text":"[tool.mypy] plugins","type":"text","marks":[{"type":"code_inline"}]},{"text":" from the repo's config as in-process Python; ","type":"text"},{"text":"--mypy \"uv run mypy\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"\"poetry run mypy\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" resolve (and can run) the repo's dependencies; the TS side loads the repo's own ","type":"text"},{"text":"typescript","type":"text","marks":[{"type":"code_inline"}]},{"text":" package. Run the scan only on repositories you would be willing to run ","type":"text"},{"text":"mypy","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"tsc","type":"text","marks":[{"type":"code_inline"}]},{"text":" in yourself.","type":"text"}]},{"type":"paragraph","content":[{"text":"Note: when installed as a plugin, a write-time PreToolUse hook may also be active — if a test-file Write/Edit is denied with a \"captain-obvious:\" reason during cleanup rewrites, fix the flagged assertions instead of re-trying the same content (see ","type":"text"},{"text":"references/prevention.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"). Both scanners also support ","type":"text"},{"text":"--file \u003cpath> [--stdin]","type":"text","marks":[{"type":"code_inline"}]},{"text":" for a syntactic-only single-file scan (JSON to stdout; no mypy/tsc, no side effects).","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. Scan (report-only)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"node \u003cskill-dir>/scripts/captain_obvious_ts.mjs --project \u003crepo> --json /tmp/co-ts.json\npython3 \u003cskill-dir>/scripts/captain_obvious_py.py --path \u003crepo> --json /tmp/co-py.json","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The Python detector shells out to mypy for the type-guaranteed category. Use the project's own environment: pass ","type":"text"},{"text":"--mypy \"uv run mypy\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" for uv projects, ","type":"text"},{"text":"--mypy \"poetry run mypy\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" for poetry, etc. If mypy isn't available it degrades gracefully to the syntactic categories.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Note: the mypy pass briefly writes ","type":"text"},{"text":"_cap_obv_shadow_*","type":"text","marks":[{"type":"code_inline"}]},{"text":" copies next to test files (removed when the run ends) — so a \"report-only\" scan does touch the working tree. Pass ","type":"text"},{"text":"--no-types","type":"text","marks":[{"type":"code_inline"}]},{"text":" for a strictly read-only scan; if the tree is not writable the scan degrades to syntactic categories and says so.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The TS detector resolves the project's own ","type":"text"},{"text":"typescript","type":"text","marks":[{"type":"code_inline"}]},{"text":" package; without a tsconfig it degrades to syntactic categories.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If the project already produces coverage","type":"text","marks":[{"type":"strong"}]},{"text":" (or you can cheaply run it), pass ","type":"text"},{"text":"--coverage \u003cfile>","type":"text","marks":[{"type":"code_inline"}]},{"text":" (lcov / istanbul ","type":"text"},{"text":"coverage-final.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" / coverage.py ","type":"text"},{"text":"coverage json","type":"text","marks":[{"type":"code_inline"}]},{"text":"). This is the dynamic half of the ICSE'19 rotten-green analysis: a ","type":"text"},{"text":"conditional-assert","type":"text","marks":[{"type":"code_inline"}]},{"text":" whose line never ran is promoted to ","type":"text"},{"text":"proven rotten","type":"text","marks":[{"type":"strong"}]},{"text":", and one that did run is dropped as a confirmed false positive. It turns the noisiest advisory category into a trustworthy one — use it whenever coverage is available.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Show the user the summary table and the findings before deleting anything.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3a. Check test value beyond the scanner","type":"text"}]},{"type":"paragraph","content":[{"text":"The scripts find mechanical patterns; they cannot decide whether a test owns a useful contract or merely repeats another test. For a focused manual audit, apply the authoring gate to each review lead or advisory before changing it.","type":"text"}]},{"type":"paragraph","content":[{"text":"Look especially for expectations copied from the implementation, source-text greps, fixtures or mocks that manufacture the asserted result, and negative controls that pass because an unrelated guard rejects the input. These are ","type":"text"},{"text":"review leads","type":"text","marks":[{"type":"strong"}]},{"text":", not new proven scanner categories. Read the complete test, the production path, overlapping tests, and relevant history before deciding. Keep tests that independently lock a public API, protocol, security boundary, platform behavior, or release artifact, even if they inspect source or run slowly. A behavior-preserving refactor breaking a test is a reason to examine it, not sufficient evidence to delete it.","type":"text"}]},{"type":"paragraph","content":[{"text":"Before a manual deletion or rewrite, record the test and location, what it can actually detect, the stronger remaining test (or why none is needed), non-test callers of any seam to be removed, relevant history, and the focused validation command. If the evidence is incomplete, keep the test pending investigation.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"4. Understand the two levels","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"proven","type":"text","marks":[{"type":"strong"}]},{"text":" — cannot fail, by construction. The scripts guard the known escape hatches (","type":"text"},{"text":"any","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"unknown","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"as","type":"text","marks":[{"type":"code_inline"}]},{"text":" casts, ","type":"text"},{"text":"!","type":"text","marks":[{"type":"code_inline"}]},{"text":", index signatures, unchecked index access, structural ","type":"text"},{"text":"instanceof","type":"text","marks":[{"type":"code_inline"}]},{"text":", custom assertion helpers). Those marked ","type":"text"},{"text":"deletable: safe","type":"text","marks":[{"type":"code_inline"}]},{"text":" are auto-deleted; proven ","type":"text"},{"text":"report-only","type":"text","marks":[{"type":"code_inline"}]},{"text":" findings (swallowed or missed-fail asserts) need a rewrite and ","type":"text"},{"text":"--fix","type":"text","marks":[{"type":"code_inline"}]},{"text":" leaves them.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"advisory","type":"text","marks":[{"type":"strong"}]},{"text":" — almost certainly useless but ","type":"text"},{"text":"not","type":"text","marks":[{"type":"em"}]},{"text":" provable (assertion-free tests, structural instanceof, mock-echo variants, index-signature-backed checks, rotten-green conditional asserts, unawaited async assertions). The script never auto-deletes these, but it records ","type":"text"},{"text":"exactly why","type":"text","marks":[{"type":"em"}]},{"text":" each is uncertain, plus a ","type":"text"},{"text":"deletable","type":"text","marks":[{"type":"code_inline"}]},{"text":" hint (","type":"text"},{"text":"aggressive","type":"text","marks":[{"type":"code_inline"}]},{"text":" = usually a deletion, ","type":"text"},{"text":"report-only","type":"text","marks":[{"type":"code_inline"}]},{"text":" = usually needs a rewrite). That reason is a question ","type":"text"},{"text":"you","type":"text","marks":[{"type":"strong"}]},{"text":" are equipped to answer against the surrounding code — so advisories are adjudicated by you (step 6), not dumped on the user.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"references/detectors.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" for the full category catalog and the reasoning behind each guard.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"5. Fix the proven tier (deterministic)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"node \u003cskill-dir>/scripts/captain_obvious_ts.mjs --project \u003crepo> --fix\npython3 \u003cskill-dir>/scripts/captain_obvious_py.py --path \u003crepo> --fix","type":"text"}]},{"type":"paragraph","content":[{"text":"Plain ","type":"text"},{"text":"--fix","type":"text","marks":[{"type":"code_inline"}]},{"text":" removes only ","type":"text"},{"text":"proven","type":"text","marks":[{"type":"strong"}]},{"text":" findings marked ","type":"text"},{"text":"deletable: safe","type":"text","marks":[{"type":"code_inline"}]},{"text":" — no judgment required, no LLM. This is the safe deterministic core; run it first. Proven ","type":"text"},{"text":"report-only","type":"text","marks":[{"type":"code_inline"}]},{"text":" findings stay for you to rewrite in step 6.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"6. Adjudicate the advisory tier (you decide, then confirm)","type":"text"}]},{"type":"paragraph","content":[{"text":"Advisories are the cases determinism ","type":"text"},{"text":"can't","type":"text","marks":[{"type":"em"}]},{"text":" settle — and that's your job, not a report line for the user. Do ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" just forward the list. For each advisory finding:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read the test and the code it exercises. The finding's ","type":"text"},{"text":"reason","type":"text","marks":[{"type":"code_inline"}]},{"text":" field is a pointed question — e.g. ","type":"text"},{"text":"\"structural instanceof — a shaped non-instance could sneak in\"","type":"text","marks":[{"type":"em"}]},{"text":" → check whether anything actually constructs a non-instance of that type; ","type":"text"},{"text":"\"mock-echo, indirect\"","type":"text","marks":[{"type":"em"}]},{"text":" → check whether a real code path runs between stub and assert. Apply the four value questions above before removing an advisory: identify the contract's strongest test owner and check whether this test protects a distinct failure mode. For a bug regression, confirm that the test fails on the pre-fix behavior for the intended reason when a safe baseline is available; a mock that merely produces the expected result is not proof.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Decide one of: ","type":"text"},{"text":"delete","type":"text","marks":[{"type":"strong"}]},{"text":" (the doubt doesn't hold — it really is useless), ","type":"text"},{"text":"keep","type":"text","marks":[{"type":"strong"}]},{"text":" (the doubt holds — it's a real check), or ","type":"text"},{"text":"rewrite","type":"text","marks":[{"type":"strong"}]},{"text":" (the intent is valid but the assertion is broken). Rewrite is the advisory tier's real value: fix the unawaited ","type":"text"},{"text":".rejects","type":"text","marks":[{"type":"code_inline"}]},{"text":" (","type":"text"},{"text":"await","type":"text","marks":[{"type":"code_inline"}]},{"text":" it), narrow a ","type":"text"},{"text":"pytest.raises(Exception)","type":"text","marks":[{"type":"code_inline"}]},{"text":" to the specific type, repair a rotten-green ","type":"text"},{"text":"conditional-assert","type":"text","marks":[{"type":"code_inline"}]},{"text":" so it actually runs. Note ","type":"text"},{"text":"no-assert","type":"text","marks":[{"type":"code_inline"}]},{"text":" findings are ","type":"text"},{"text":"smoke tests","type":"text","marks":[{"type":"strong"}]},{"text":" — legitimate by design (ICSE'19); default to ","type":"text"},{"text":"keep","type":"text","marks":[{"type":"strong"}]},{"text":" unless the test clearly ","type":"text"},{"text":"meant","type":"text","marks":[{"type":"em"}]},{"text":" to assert something and forgot.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Propose before acting.","type":"text","marks":[{"type":"strong"}]},{"text":" Present a compact per-item table — finding, verdict, one-line rationale, and the exact edit for rewrites — and apply only what the user approves. Never auto-delete or auto-rewrite an advisory.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"For a large advisory set, delegate the per-item code reads to a ","type":"text"},{"text":"cheaper, faster subagent model","type":"text","marks":[{"type":"strong"}]},{"text":" (batch the findings; have it return verdict + rationale + proposed edit per item) and keep the final proposal/synthesis here — don't burn the main loop reading files one by one. The proven tier is never handed to a subagent; it's already decided.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"7. Clean the residue","type":"text"}]},{"type":"paragraph","content":[{"text":"The scripts delete whole test blocks or individual assertion lines. That can leave behind: unused imports/variables (","type":"text"},{"text":"noUnusedLocals","type":"text","marks":[{"type":"code_inline"}]},{"text":" will flag them), empty ","type":"text"},{"text":"describe()","type":"text","marks":[{"type":"code_inline"}]},{"text":" blocks, empty test classes, orphaned fixtures/mocks. Fix those by hand — the typechecker output is your worklist.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"8. Verify","type":"text"}]},{"type":"paragraph","content":[{"text":"Run the project's typecheck AND full test suite (","type":"text"},{"text":"tsc --noEmit","type":"text","marks":[{"type":"code_inline"}]},{"text":" + the test command from package.json / ","type":"text"},{"text":"pytest","type":"text","marks":[{"type":"code_inline"}]},{"text":"). Everything must pass with the same result as before (minus the deleted tests). If anything regresses, ","type":"text"},{"text":"git checkout -- \u003cfiles>","type":"text","marks":[{"type":"code_inline"}]},{"text":" and report what happened instead of pushing through.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"9. Report","type":"text"}]},{"type":"paragraph","content":[{"text":"Tell the user: proven tests/assertions removed (per-category counts, lines saved), the advisory verdicts you applied (deleted / rewritten, with the fix), and anything you chose to ","type":"text"},{"text":"keep","type":"text","marks":[{"type":"strong"}]},{"text":" with the reason the doubt held — that last group is the tool earning trust, not failing.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"What NOT to flag (the scripts already know, but so should you)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"toBeDefined()","type":"text","marks":[{"type":"code_inline"}]},{"text":" on ","type":"text"},{"text":".find()","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"Map.get()","type":"text","marks":[{"type":"code_inline"}]},{"text":" results — the type is ","type":"text"},{"text":"T | undefined","type":"text","marks":[{"type":"code_inline"}]},{"text":", the check is real.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enum/constant contract locks (","type":"text"},{"text":"expect(ExitCode.OK).toBe(0)","type":"text","marks":[{"type":"code_inline"}]},{"text":") — they catch renumbering.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Assertions on values read from files/APIs at test time — real regression tests.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tests asserting via custom helpers (","type":"text"},{"text":"expectAllow(x)","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"self._check(...)","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Must not raise\" contract tests for fail-open code paths.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When not to run the cleanup scanner","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Mid red-green.","type":"text","marks":[{"type":"strong"}]},{"text":" During TDD a test is ","type":"text"},{"text":"supposed","type":"text","marks":[{"type":"em"}]},{"text":" to be failing, and a freshly-written test may not have its assertion yet. Use the authoring gate, but run the cleanup scanner only once the suite is green.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"On a branch under review.","type":"text","marks":[{"type":"strong"}]},{"text":" Scan (","type":"text"},{"text":"--json","type":"text","marks":[{"type":"code_inline"}]},{"text":") is fine; ","type":"text"},{"text":"--fix","type":"text","marks":[{"type":"code_inline"}]},{"text":" is not. Rewriting test files while a reviewer or a merge gate is reading the diff invalidates what they reviewed.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"As a coverage or CI-time optimizer.","type":"text","marks":[{"type":"strong"}]},{"text":" It deletes tests that cannot fail, which is a correctness argument, not a speed one. \"CI is slow\" is not a reason to reach for it — a slow suite full of real tests stays slow.","type":"text"}]}]}]}]},"metadata":{"date":"2026-11-02","name":"captain-obvious","author":"@skillopedia","source":{"stars":15,"repo_name":"captain-obvious","origin_url":"https://github.com/shmulc8/captain-obvious/blob/HEAD/skills/captain-obvious/SKILL.md","repo_owner":"shmulc8","body_sha256":"7c81631049ee233af4f80a2e46b5128062ffed2187715b1d9b13e8dd849d3d6e","cluster_key":"3bfa07f72bb5b8c69150fdfed9d0324432b1dc52508677d1aa4baea6629269a4","clean_bundle":{"format":"clean-skill-bundle-v1","source":"shmulc8/captain-obvious/skills/captain-obvious/SKILL.md","text_bytes":170953,"source_commit":"baa046f7a7276a524a3c740e8e4b098a11449a98","skills_sh_rank":9913,"attachment_count":26,"text_attachments":26,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/captain-obvious/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"testing-qa","category_label":"Testing"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"testing-qa","import_tag":"skills-sh-top20k-2026-11","description":"Audit TypeScript and Python tests for assertions that cannot fail or check nothing, and guide test authoring with a contract and regression gate. Use when writing or changing tests to avoid low-value coverage, or cleaning redundant, tautological, duplicated, or AI-generated tests. Cleanup runs bundled deterministic scanners; authoring guidance needs no scan during red-green TDD."}},"renderedAt":1793666098290}

Captain Obvious Deletes tests that assert what is already guaranteed — by the compiler, by the mock framework, or by the laws of logic. These tests burn CI time, inflate coverage confidence, and can never catch a regression. They are the signature of AI-generated test suites (empirical studies find test smells in 38–100% of LLM-generated tests). For cleanup, two deterministic scripts in do the heavy lifting. Run them, interpret the report, clean up the residue, and verify nothing broke. Do not hand-scan test files or spawn subagents per file — one script invocation scans the whole project. Du…