582 lines
58 KiB
HTML
582 lines
58 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="google-site-verification" content="899Jw4jb5ux928e2-cYHEoRy70zaMqWIXL-7YK1Nd2U" />
|
||
<title>brooks-lint — AI code reviews grounded in twelve classic engineering books</title>
|
||
<meta name="description" content="brooks-lint diagnoses your code against twelve classic software engineering books, producing structured Symptom → Source → Consequence → Remedy findings every time.">
|
||
<link rel="icon" type="image/svg+xml" href="logo.svg">
|
||
<!-- Open Graph -->
|
||
<meta property="og:title" content="brooks-lint">
|
||
<meta property="og:description" content="AI code reviews grounded in twelve classic engineering books. Consistent. Traceable. Actionable.">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://hyhmrright.github.io/brooks-lint/">
|
||
<meta property="og:image" content="https://hyhmrright.github.io/brooks-lint/hero.png">
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
<meta name="twitter:title" content="brooks-lint — AI code reviews grounded in twelve engineering classics">
|
||
<meta name="twitter:description" content="Decay-risk diagnostics with book citations, severity labels, and a 0–100 Health Score. Consistent. Traceable. Actionable.">
|
||
<meta name="twitter:image" content="https://hyhmrright.github.io/brooks-lint/hero.png">
|
||
<link rel="canonical" href="https://hyhmrright.github.io/brooks-lint/">
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@type": "SoftwareApplication",
|
||
"name": "brooks-lint",
|
||
"applicationCategory": "DeveloperApplication",
|
||
"operatingSystem": "Claude Code, Gemini CLI, Codex CLI, GitHub Actions",
|
||
"description": "AI code reviews grounded in twelve classic software engineering books. Decay-risk diagnostics with book citations, severity labels, and six analysis modes including full-sweep auto-fix.",
|
||
"url": "https://hyhmrright.github.io/brooks-lint/",
|
||
"image": "https://hyhmrright.github.io/brooks-lint/hero.png",
|
||
"softwareVersion": "1.4.0",
|
||
"license": "https://github.com/hyhmrright/brooks-lint/blob/main/LICENSE",
|
||
"codeRepository": "https://github.com/hyhmrright/brooks-lint",
|
||
"keywords": "AI code review, code quality, tech debt, architecture audit, test quality, Claude Code plugin, refactoring, clean architecture",
|
||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" }
|
||
}
|
||
</script>
|
||
<style>
|
||
:root {
|
||
--paper: #f7f1e4;
|
||
--paper-2: #fbf6ec;
|
||
--card: #fffdf8;
|
||
--ink: #2a2520;
|
||
--ink-soft: #5c5347;
|
||
--rule: #e3d8c2;
|
||
--rule-soft: #ece2cf;
|
||
--blue: #2d4a7c;
|
||
--blue-soft: #e7edf5;
|
||
--green: #2b8a3e;
|
||
--gold: #b07d2b;
|
||
--red: #b23b3b;
|
||
--ink-dark: #211d18;
|
||
--serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
|
||
--sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", Roboto, Helvetica, Arial, sans-serif;
|
||
--mono: "SF Mono", "JetBrains Mono", "Fira Code", Menlo, Consolas, monospace;
|
||
}
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
html { scroll-behavior: smooth; }
|
||
body {
|
||
font-family: var(--sans);
|
||
color: var(--ink);
|
||
background: var(--paper);
|
||
line-height: 1.65;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
.wrap { max-width: 1080px; margin: 0 auto; padding: 0 24px; }
|
||
h1, h2, h3, .serif { font-family: var(--serif); font-weight: 700; letter-spacing: -0.01em; }
|
||
a { color: var(--blue); text-decoration: none; }
|
||
a:hover { text-decoration: underline; }
|
||
|
||
/* paper grain overlay */
|
||
body::before {
|
||
content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
|
||
background-image: radial-gradient(rgba(120,90,40,0.04) 1px, transparent 1px);
|
||
background-size: 4px 4px; opacity: .6;
|
||
}
|
||
main, nav, footer { position: relative; z-index: 1; }
|
||
|
||
/* ---- Nav ---- */
|
||
nav {
|
||
position: sticky; top: 0; z-index: 50;
|
||
background: rgba(247,241,228,0.85);
|
||
backdrop-filter: saturate(140%) blur(10px);
|
||
border-bottom: 1px solid var(--rule);
|
||
}
|
||
.nav-in { display: flex; align-items: center; gap: 20px; height: 64px; }
|
||
.brand { display: flex; align-items: center; gap: 10px; font-family: var(--serif); font-weight: 700; font-size: 19px; color: var(--ink); }
|
||
.brand img { width: 30px; height: 30px; border-radius: 7px; }
|
||
.nav-links { display: flex; gap: 22px; margin-left: auto; align-items: center; }
|
||
.nav-links a { color: var(--ink-soft); font-size: 14.5px; }
|
||
.nav-links a:hover { color: var(--ink); text-decoration: none; }
|
||
.lang-toggle {
|
||
display: inline-flex; border: 1px solid var(--rule); border-radius: 999px; overflow: hidden;
|
||
font-size: 13px; background: var(--card);
|
||
}
|
||
.lang-toggle button {
|
||
border: none; background: transparent; padding: 5px 12px; cursor: pointer;
|
||
color: var(--ink-soft); font-family: var(--sans); font-weight: 600;
|
||
}
|
||
.lang-toggle button.active { background: var(--ink); color: var(--paper-2); }
|
||
.btn {
|
||
display: inline-block; padding: 10px 20px; border-radius: 8px; font-weight: 600; font-size: 15px;
|
||
border: 1px solid transparent; cursor: pointer; transition: transform .08s ease, box-shadow .15s ease;
|
||
}
|
||
.btn:hover { text-decoration: none; transform: translateY(-1px); }
|
||
.btn-primary { background: var(--ink); color: var(--paper-2); box-shadow: 0 2px 0 var(--gold); }
|
||
.btn-ghost { background: var(--card); color: var(--ink); border-color: var(--rule); }
|
||
@media (max-width: 720px) { .nav-links a.hide-sm { display: none; } }
|
||
|
||
/* ---- Hero ---- */
|
||
.hero { padding: 76px 0 56px; text-align: center; }
|
||
.eyebrow {
|
||
display: inline-block; font-family: var(--mono); font-size: 12.5px; letter-spacing: .12em;
|
||
text-transform: uppercase; color: var(--gold); border: 1px solid var(--rule);
|
||
padding: 5px 12px; border-radius: 999px; margin-bottom: 22px; background: var(--card);
|
||
}
|
||
.hero h1 { font-size: clamp(34px, 5.4vw, 56px); line-height: 1.08; max-width: 18ch; margin: 0 auto 18px; }
|
||
.hero .lede { font-size: clamp(17px, 2.2vw, 20px); color: var(--ink-soft); max-width: 60ch; margin: 0 auto 14px; }
|
||
.quote {
|
||
max-width: 56ch; margin: 26px auto 8px; font-family: var(--serif); font-style: italic;
|
||
font-size: 18px; color: var(--ink); border-left: 3px solid var(--gold); padding-left: 18px; text-align: left;
|
||
}
|
||
.quote cite { display: block; font-style: normal; font-size: 14px; color: var(--ink-soft); margin-top: 6px; }
|
||
.cta-row { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-top: 30px; }
|
||
.hero-shot { margin: 46px auto 0; max-width: 900px; }
|
||
.hero-shot img { width: 100%; height: auto; border-radius: 14px; border: 1px solid var(--rule);
|
||
box-shadow: 0 18px 50px rgba(80,55,15,.16); display: block; }
|
||
|
||
/* ---- Stat strip ---- */
|
||
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--rule);
|
||
border: 1px solid var(--rule); border-radius: 12px; overflow: hidden; margin-top: 52px; }
|
||
.stat { background: var(--card); padding: 22px 14px; text-align: center; }
|
||
.stat b { display: block; font-family: var(--serif); font-size: clamp(26px, 4vw, 36px); color: var(--blue); line-height: 1; }
|
||
.stat span { font-size: 13px; color: var(--ink-soft); display: block; margin-top: 8px; }
|
||
@media (max-width: 640px) { .stats { grid-template-columns: repeat(2, 1fr); } }
|
||
|
||
/* ---- Section scaffolding ---- */
|
||
section { padding: 64px 0; }
|
||
.section-head { text-align: center; max-width: 64ch; margin: 0 auto 44px; }
|
||
.section-head h2 { font-size: clamp(26px, 3.6vw, 38px); margin-bottom: 12px; }
|
||
.section-head p { color: var(--ink-soft); font-size: 17px; }
|
||
.alt { background: var(--paper-2); border-top: 1px solid var(--rule-soft); border-bottom: 1px solid var(--rule-soft); }
|
||
|
||
/* ---- Feature grid ---- */
|
||
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
|
||
@media (max-width: 900px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
|
||
@media (max-width: 520px) { .grid-4 { grid-template-columns: 1fr; } }
|
||
.feature { background: var(--card); border: 1px solid var(--rule); border-radius: 12px; padding: 24px; }
|
||
.feature .ic { font-size: 26px; margin-bottom: 12px; display: block; }
|
||
.feature h3 { font-size: 18px; margin-bottom: 8px; }
|
||
.feature p { font-size: 14.5px; color: var(--ink-soft); }
|
||
|
||
/* ---- Decay risks ---- */
|
||
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
|
||
@media (max-width: 860px) { .grid-3 { grid-template-columns: repeat(2, 1fr); } }
|
||
@media (max-width: 540px) { .grid-3 { grid-template-columns: 1fr; } }
|
||
.risk { background: var(--card); border: 1px solid var(--rule); border-left: 4px solid var(--blue);
|
||
border-radius: 10px; padding: 20px; }
|
||
.risk .code { font-family: var(--mono); font-size: 12px; color: var(--gold); font-weight: 700; letter-spacing: .06em; }
|
||
.risk h3 { font-size: 17px; margin: 4px 0 8px; }
|
||
.risk p { font-size: 14px; color: var(--ink-soft); }
|
||
.risk .src { font-size: 12px; color: var(--ink-soft); margin-top: 12px; font-style: italic; opacity: .85; }
|
||
|
||
/* ---- Sample finding ---- */
|
||
.sample { background: var(--ink-dark); border-radius: 14px; padding: 30px; color: #e9e2d3; font-size: 15px; }
|
||
.sample .score { font-family: var(--serif); font-size: 22px; color: #fff; margin-bottom: 6px; }
|
||
.sample .score b { color: var(--red); }
|
||
.sample .summary { color: #b9b0a0; font-style: italic; font-size: 14.5px; margin-bottom: 22px; }
|
||
.finding { border-top: 1px solid #3a342c; padding-top: 18px; margin-top: 18px; }
|
||
.finding h4 { font-family: var(--serif); font-size: 16px; color: #fff; margin-bottom: 10px; }
|
||
.finding .dot { color: var(--red); }
|
||
.finding .row { font-size: 14px; margin-bottom: 7px; line-height: 1.55; }
|
||
.finding .row b { color: var(--gold); font-weight: 700; }
|
||
.finding .row.src b { color: #7fa8e0; }
|
||
.finding .row.fix b { color: #6fcf83; }
|
||
|
||
/* ---- Benchmark table ---- */
|
||
.table-wrap { overflow-x: auto; border: 1px solid var(--rule); border-radius: 12px; background: var(--card); }
|
||
table { width: 100%; border-collapse: collapse; font-size: 15px; min-width: 460px; }
|
||
th, td { padding: 13px 18px; text-align: left; border-bottom: 1px solid var(--rule-soft); }
|
||
th { font-family: var(--serif); font-size: 15px; }
|
||
td.c, th.c { text-align: center; }
|
||
tr:last-child td { border-bottom: none; }
|
||
tbody tr:last-child { font-weight: 700; background: var(--blue-soft); }
|
||
.yes { color: var(--green); font-weight: 700; }
|
||
.no { color: var(--red); font-weight: 700; }
|
||
|
||
/* ---- Books ---- */
|
||
.books { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; max-width: 880px; margin: 0 auto; }
|
||
.book-chip { background: var(--card); border: 1px solid var(--rule); border-radius: 8px;
|
||
padding: 9px 14px; font-size: 14px; }
|
||
.book-chip b { font-family: var(--serif); }
|
||
.book-chip span { color: var(--ink-soft); font-size: 12.5px; }
|
||
|
||
/* ---- Install ---- */
|
||
.code-block { position: relative; background: var(--ink-dark); border-radius: 12px; padding: 22px 22px;
|
||
font-family: var(--mono); font-size: 14px; color: #e9e2d3; overflow-x: auto; margin-bottom: 16px; }
|
||
.code-block .cmt { color: #8a8170; }
|
||
.code-block .tok { color: #6fcf83; }
|
||
.copy-btn { position: absolute; top: 12px; right: 12px; background: #3a342c; color: #cfc7b6;
|
||
border: none; border-radius: 6px; padding: 5px 11px; font-size: 12px; cursor: pointer; font-family: var(--sans); }
|
||
.copy-btn:hover { background: #4a4338; }
|
||
.install-grid { display: grid; grid-template-columns: 1fr; gap: 0; max-width: 760px; margin: 0 auto; }
|
||
.install-label { font-family: var(--serif); font-size: 18px; margin: 18px 0 10px; }
|
||
|
||
/* ---- Footer ---- */
|
||
footer { border-top: 1px solid var(--rule); padding: 40px 0 56px; background: var(--paper-2); }
|
||
.foot-in { display: flex; flex-wrap: wrap; gap: 18px; align-items: center; justify-content: space-between; }
|
||
.foot-links { display: flex; gap: 20px; flex-wrap: wrap; }
|
||
.foot-links a { color: var(--ink-soft); font-size: 14px; }
|
||
.foot-note { font-size: 13px; color: var(--ink-soft); }
|
||
|
||
[data-lang-hide] { display: none !important; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<nav>
|
||
<div class="wrap nav-in">
|
||
<a class="brand" href="#top"><img src="logo.svg" alt="brooks-lint logo">brooks-lint</a>
|
||
<div class="nav-links">
|
||
<a class="hide-sm" href="#risks" data-en="Decay Risks" data-zhtw="衰退風險" data-ja="劣化リスク" data-ko="쇠퇴 위험" data-es="Riesgos de deterioro" data-zh="腐化风险">Decay Risks</a>
|
||
<a class="hide-sm" href="#sample" data-en="Example" data-zhtw="範例" data-ja="実例" data-ko="예시" data-es="Ejemplo" data-zh="示例">Example</a>
|
||
<a class="hide-sm" href="#benchmark" data-en="Benchmark" data-zhtw="基準測試" data-ja="ベンチマーク" data-ko="벤치마크" data-es="Benchmark" data-zh="基准">Benchmark</a>
|
||
<a class="hide-sm" href="gallery.html" data-en="Gallery" data-zhtw="範例展示" data-ja="ギャラリー" data-ko="갤러리" data-es="Galería" data-zh="画廊">Gallery</a>
|
||
<a class="hide-sm" href="guide.html" data-en="Guide" data-zhtw="指南" data-ja="ガイド" data-ko="가이드" data-es="Guía" data-zh="指南">Guide</a>
|
||
<a class="hide-sm" href="#install" data-en="Install" data-zhtw="安裝" data-ja="インストール" data-ko="설치" data-es="Instalación" data-zh="安装">Install</a>
|
||
<span class="lang-toggle">
|
||
<button data-set-lang="en">EN</button>
|
||
<button data-set-lang="zh">中</button>
|
||
<button data-set-lang="zhtw">繁</button>
|
||
<button data-set-lang="ja">日</button>
|
||
<button data-set-lang="ko">한</button>
|
||
<button data-set-lang="es">ES</button>
|
||
</span>
|
||
<a href="https://github.com/hyhmrright/brooks-lint" target="_blank" rel="noopener">GitHub ↗</a>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<main id="top">
|
||
|
||
<!-- HERO -->
|
||
<header class="hero">
|
||
<div class="wrap">
|
||
<span class="eyebrow" data-en="Claude Code · Codex · Gemini plugin" data-zhtw="Claude Code · Codex · Gemini 外掛" data-ja="Claude Code · Codex · Gemini プラグイン" data-ko="Claude Code · Codex · Gemini 플러그인" data-es="Plugin para Claude Code · Codex · Gemini" data-zh="Claude Code · Codex · Gemini 插件">Claude Code · Codex · Gemini plugin</span>
|
||
<h1 data-en="AI code reviews grounded in twelve classic engineering books" data-zhtw="扎根於十二本經典工程著作的 AI 程式碼審查" data-ja="十二冊の古典的工学書に根ざした AI コードレビュー" data-ko="열두 권의 고전 엔지니어링 도서에 뿌리내린 AI 코드 리뷰" data-es="Revisiones de código con IA fundamentadas en doce libros clásicos de ingeniería"
|
||
data-zh="扎根于十二本经典工程著作的 AI 代码审查">AI code reviews grounded in twelve classic engineering books</h1>
|
||
<p class="lede"
|
||
data-en="Most tools count lines and complexity. brooks-lint diagnoses your code against twelve decay risks synthesized from the classics — every finding cited, scored, and remedied." data-zhtw="多數工具只計算行數和複雜度。brooks-lint 對照從經典提煉的十二類衰退風險逐一診斷你的程式碼——每條結論都有出處、有評分、有對策。" data-ja="ほとんどのツールは行数と複雑度を数えるだけです。brooks-lint は古典から統合した十二の劣化リスクに照らしてコードを診断します——すべての指摘に出典、スコア、対策が付きます。" data-ko="대부분의 도구는 줄 수와 복잡도만 셉니다. brooks-lint는 고전에서 종합한 열두 가지 쇠퇴 위험에 비추어 코드를 진단합니다 — 모든 진단에 출처, 점수, 처방이 따릅니다." data-es="La mayoría de las herramientas cuentan líneas y complejidad. brooks-lint diagnostica tu código frente a doce riesgos de deterioro sintetizados de los clásicos — cada hallazgo citado, puntuado y con remedio."
|
||
data-zh="多数工具只统计行数和复杂度。brooks-lint 把你的代码对照从十二本经典提炼的腐化风险逐一诊断——每条结论都有出处、有评分、有修复方案。">
|
||
Most tools count lines and complexity. brooks-lint diagnoses your code against twelve decay risks synthesized from the classics — every finding cited, scored, and remedied.
|
||
</p>
|
||
<blockquote class="quote"
|
||
data-en="“The bearing of a child takes nine months, no matter how many women are assigned.”" data-zhtw="「一個孩子的孕育需要九個月,無論你派多少人去。」" data-ja="「一人の子を産むには九か月かかる。何人の女性を割り当てようとも。」" data-ko="“아이를 낳는 데는 아홉 달이 걸린다. 몇 명의 여성을 투입하든 마찬가지다.”" data-es="“Gestar un niño toma nueve meses, sin importar cuántas mujeres se asignen.”"
|
||
data-zh="“一个孩子的孕育需要九个月,无论你派多少人去。”">
|
||
“The bearing of a child takes nine months, no matter how many women are assigned.”
|
||
<cite data-en="— Frederick Brooks, The Mythical Man-Month (1975)" data-zhtw="—— 弗雷德里克·布魯克斯,《人月神話》(1975)" data-ja="— フレデリック・ブルックス『人月の神話』(1975)" data-ko="— 프레더릭 브룩스, 『맨먼스 미신』(1975)" data-es="— Frederick Brooks, The Mythical Man-Month (1975)" data-zh="—— 弗雷德里克·布鲁克斯,《人月神话》(1975)">— Frederick Brooks, The Mythical Man-Month (1975)</cite>
|
||
</blockquote>
|
||
<div class="cta-row">
|
||
<a class="btn btn-primary" href="#install" data-en="Get Started" data-zhtw="開始使用" data-ja="はじめる" data-ko="시작하기" data-es="Empezar" data-zh="开始使用">Get Started</a>
|
||
<a class="btn btn-ghost" href="https://github.com/hyhmrright/brooks-lint" target="_blank" rel="noopener" data-en="View on GitHub" data-zhtw="在 GitHub 查看" data-ja="GitHub で見る" data-ko="GitHub에서 보기" data-es="Ver en GitHub" data-zh="GitHub 查看">View on GitHub</a>
|
||
</div>
|
||
|
||
<div style="margin-top: 26px; text-align: center;">
|
||
<a href="https://trendshift.io/repositories/47738" target="_blank" rel="noopener"><img src="https://trendshift.io/api/badge/trendshift/repositories/47738/daily?language=JavaScript" alt="#2 JavaScript Repository of the Day | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"></a>
|
||
</div>
|
||
|
||
<div style="margin-top: 30px; text-align: center;">
|
||
<img src="banner-en.svg"
|
||
data-src-en="banner-en.svg" data-src-zh="banner-zh-CN.svg" data-src-zhtw="banner-zh-TW.svg"
|
||
data-src-ja="banner-ja.svg" data-src-ko="banner-ko.svg" data-src-es="banner-es.svg"
|
||
alt="Your code → 12 classics → 12 decay risks → cited findings"
|
||
style="width: 100%; max-width: 820px; height: auto;">
|
||
</div>
|
||
|
||
<div class="hero-shot">
|
||
<img src="demo.gif" alt="brooks-lint reviewing code: a /brooks-review command produces a 28/100 health score and cited Symptom → Source → Consequence → Remedy findings" loading="eager">
|
||
</div>
|
||
|
||
<div class="stats">
|
||
<div class="stat"><b>12</b><span data-en="classic books" data-zhtw="本經典著作" data-ja="冊の古典" data-ko="권의 고전" data-es="libros clásicos" data-zh="本经典著作">classic books</span></div>
|
||
<div class="stat"><b>12</b><span data-en="decay risks (R1–R6 · T1–T6)" data-zhtw="衰退風險(R1–R6 · T1–T6)" data-ja="劣化リスク(R1–R6 · T1–T6)" data-ko="쇠퇴 위험 (R1–R6 · T1–T6)" data-es="riesgos de deterioro (R1–R6 · T1–T6)" data-zh="腐化风险 (R1–R6 · T1–T6)">decay risks (R1–R6 · T1–T6)</span></div>
|
||
<div class="stat"><b>94%</b><span data-en="benchmark pass rate" data-zhtw="基準通過率" data-ja="ベンチマーク合格率" data-ko="벤치마크 통과율" data-es="tasa de aprobación del benchmark" data-zh="基准通过率">benchmark pass rate</span></div>
|
||
<div class="stat"><b>6</b><span data-en="independent skills" data-zhtw="個獨立技能" data-ja="つの独立したスキル" data-ko="개의 독립 스킬" data-es="skills independientes" data-zh="个独立技能">independent skills</span></div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- FEATURES -->
|
||
<section>
|
||
<div class="wrap">
|
||
<div class="section-head">
|
||
<h2 data-en="Not a linter. A second opinion from the canon." data-zhtw="不是 linter,而是來自經典的第二意見。" data-ja="linter ではありません。古典からのセカンドオピニオンです。" data-ko="linter가 아닙니다. 고전이 주는 세컨드 오피니언입니다." data-es="No es un linter. Una segunda opinión desde el canon." data-zh="不是 linter,是来自经典的第二意见。">Not a linter. A second opinion from the canon.</h2>
|
||
<p data-en="Linters catch syntax. brooks-lint catches architectural drift, knowledge silos, and domain distortion — the slow problems that cost teams months." data-zhtw="linter 抓語法。brooks-lint 抓架構漂移、知識孤島和領域失真——那些拖垮團隊數月的慢性問題。" data-ja="linter は構文を捉えます。brooks-lint はアーキテクチャの漂流、知識のサイロ化、ドメインの歪みを捉えます——チームに数か月を費やさせる遅効性の問題です。" data-ko="linter는 문법을 잡습니다. brooks-lint는 아키텍처 표류, 지식 사일로, 도메인 왜곡을 잡습니다 — 팀에 수개월을 허비하게 하는 느린 문제들입니다." data-es="Los linters detectan sintaxis. brooks-lint detecta la deriva arquitectónica, los silos de conocimiento y la distorsión del dominio — los problemas lentos que cuestan meses a los equipos."
|
||
data-zh="linter 抓语法。brooks-lint 抓架构漂移、知识孤岛和领域失真——那些拖垮团队数月却无人察觉的慢性病。">Linters catch syntax. brooks-lint catches architectural drift, knowledge silos, and domain distortion — the slow problems that cost teams months.</p>
|
||
</div>
|
||
<div class="grid-4">
|
||
<div class="feature">
|
||
<span class="ic">⚖️</span>
|
||
<h3 data-en="The Iron Law" data-zhtw="鐵律" data-ja="鉄の掟" data-ko="철칙" data-es="La Ley de Hierro" data-zh="铁律格式">The Iron Law</h3>
|
||
<p data-en="Every finding follows one shape: Symptom → Source → Consequence → Remedy. No vague vibes, ever." data-zhtw="每條結論遵循同一形態:症狀 → 根源 → 後果 → 對策。絕不含糊其辭。" data-ja="すべての指摘が同じ形をとります:症状 → 根源 → 結果 → 対策。曖昧な感想は一切ありません。" data-ko="모든 진단은 하나의 형태를 따릅니다: 증상 → 근원 → 결과 → 처방. 모호한 느낌은 결코 없습니다." data-es="Cada hallazgo sigue una sola forma: Síntoma → Origen → Consecuencia → Remedio. Nunca vaguedades."
|
||
data-zh="每条结论遵循同一形态:症状 → 根源 → 后果 → 修复。绝不含糊其辞。">Every finding follows one shape: Symptom → Source → Consequence → Remedy. No vague vibes, ever.</p>
|
||
</div>
|
||
<div class="feature">
|
||
<span class="ic">📚</span>
|
||
<h3 data-en="Cited to the books" data-zhtw="引用書目出處" data-ja="書籍に出典あり" data-ko="도서 출처 인용" data-es="Citado a los libros" data-zh="书有出处">Cited to the books</h3>
|
||
<p data-en="Brooks, Fowler, Martin, Ousterhout, Evans, Feathers, Meszaros and more — each finding names the author and principle." data-zhtw="布魯克斯、Fowler、Martin、Ousterhout、Evans、Feathers、Meszaros 等——每條結論都點名作者與原則。" data-ja="Brooks、Fowler、Martin、Ousterhout、Evans、Feathers、Meszaros など——各指摘が著者と原則を明示します。" data-ko="Brooks, Fowler, Martin, Ousterhout, Evans, Feathers, Meszaros 등 — 각 진단이 저자와 원칙을 명시합니다." data-es="Brooks, Fowler, Martin, Ousterhout, Evans, Feathers, Meszaros y más — cada hallazgo nombra al autor y el principio."
|
||
data-zh="布鲁克斯、Fowler、Martin、Ousterhout、Evans、Feathers、Meszaros 等——每条结论都点名作者与原则。">Brooks, Fowler, Martin, Ousterhout, Evans, Feathers, Meszaros and more — each finding names the author and principle.</p>
|
||
</div>
|
||
<div class="feature">
|
||
<span class="ic">🎯</span>
|
||
<h3 data-en="Six focused skills" data-zhtw="六個專注技能" data-ja="六つの専門スキル" data-ko="여섯 가지 집중 스킬" data-es="Seis skills enfocadas" data-zh="六个专注技能">Six focused skills</h3>
|
||
<p data-en="PR Review, Architecture Audit, Tech Debt, Test Quality, Health Dashboard, and a Full Sweep that auto-fixes." data-zhtw="PR 審查、架構審計、技術債、測試品質、健康儀表板,以及會自動修復的全面掃描。" data-ja="PR レビュー、アーキテクチャ監査、技術的負債、テスト品質、健全性ダッシュボード、そして自動修復するフルスイープ。" data-ko="PR 리뷰, 아키텍처 감사, 기술 부채, 테스트 품질, 건강 대시보드, 그리고 자동 수정하는 전체 스윕." data-es="Revisión de PR, Auditoría de Arquitectura, Deuda Técnica, Calidad de Pruebas, Panel de Salud y un Barrido Completo que corrige automáticamente."
|
||
data-zh="PR 审查、架构审计、技术债、测试质量、健康仪表盘,以及会自动修复的全面扫描。">PR Review, Architecture Audit, Tech Debt, Test Quality, Health Dashboard, and a Full Sweep that auto-fixes.</p>
|
||
</div>
|
||
<div class="feature">
|
||
<span class="ic">🔌</span>
|
||
<h3 data-en="Zero config, any language" data-zhtw="零設定,任意語言" data-ja="設定ゼロ、あらゆる言語" data-ko="설정 제로, 모든 언어" data-es="Cero configuración, cualquier lenguaje" data-zh="零配置·任意语言">Zero config, any language</h3>
|
||
<p data-en="Works in Claude Code, Codex CLI, and Gemini CLI. No plugins to wire up, no language limits." data-zhtw="支援 Claude Code、Codex CLI 與 Gemini CLI。無需接線設定,不限語言。" data-ja="Claude Code、Codex CLI、Gemini CLI で動作します。配線するプラグインも、言語の制限もありません。" data-ko="Claude Code, Codex CLI, Gemini CLI에서 작동합니다. 연결할 플러그인도, 언어 제한도 없습니다." data-es="Funciona en Claude Code, Codex CLI y Gemini CLI. Sin plugins que conectar, sin límites de lenguaje."
|
||
data-zh="支持 Claude Code、Codex CLI、Gemini CLI。无需接线,不限语言。">Works in Claude Code, Codex CLI, and Gemini CLI. No plugins to wire up, no language limits.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- DECAY RISKS -->
|
||
<section id="risks" class="alt">
|
||
<div class="wrap">
|
||
<div class="section-head">
|
||
<h2 data-en="The Six Production Decay Risks" data-zhtw="六類生產程式碼衰退風險" data-ja="六つの本番コード劣化リスク" data-ko="여섯 가지 프로덕션 코드 쇠퇴 위험" data-es="Los seis riesgos de deterioro del código de producción" data-zh="六大生产代码腐化风险">The Six Production Decay Risks</h2>
|
||
<p data-en="Synthesized from the twelve books. Six more (T1–T6) cover test-suite decay." data-zhtw="提煉自十二本經典。另有六項(T1–T6)涵蓋測試套件的衰退。" data-ja="十二冊の書籍から統合。さらに六つ(T1–T6)がテストスイートの劣化を扱います。" data-ko="열두 권의 책에서 종합. 추가 여섯 가지(T1–T6)가 테스트 스위트 쇠퇴를 다룹니다." data-es="Sintetizados a partir de los doce libros. Otros seis (T1–T6) cubren el deterioro de la suite de pruebas."
|
||
data-zh="提炼自十二本经典。另有六项(T1–T6)覆盖测试套件的腐化。">Synthesized from the twelve books. Six more (T1–T6) cover test-suite decay.</p>
|
||
</div>
|
||
<div class="grid-3">
|
||
<div class="risk">
|
||
<span class="code">R1</span>
|
||
<h3>🧠 <span data-en="Cognitive Overload" data-zhtw="認知過載" data-ja="認知的過負荷" data-ko="인지 과부하" data-es="Sobrecarga cognitiva" data-zh="认知过载">Cognitive Overload</span></h3>
|
||
<p data-en="How much mental effort does it take to understand this?" data-zhtw="理解這段程式碼要耗費多少腦力?" data-ja="これを理解するのにどれだけの精神的労力がかかるか?" data-ko="이것을 이해하는 데 얼마나 많은 정신적 노력이 드는가?" data-es="¿Cuánto esfuerzo mental cuesta entender esto?" data-zh="理解这段代码要耗费多少脑力?">How much mental effort does it take to understand this?</p>
|
||
<div class="src">Code Complete · Refactoring · DDD · Philosophy of SD</div>
|
||
</div>
|
||
<div class="risk">
|
||
<span class="code">R2</span>
|
||
<h3>🔗 <span data-en="Change Propagation" data-zhtw="變更擴散" data-ja="変更の波及" data-ko="변경 전파" data-es="Propagación de cambios" data-zh="变更扩散">Change Propagation</span></h3>
|
||
<p data-en="How many unrelated things break on one change?" data-zhtw="改一處會牽連多少無關之物崩壞?" data-ja="一つの変更でいくつの無関係なものが壊れるか?" data-ko="한 번의 변경으로 무관한 것이 얼마나 깨지는가?" data-es="¿Cuántas cosas no relacionadas se rompen con un solo cambio?" data-zh="改一处会牵连多少无关之物崩坏?">How many unrelated things break on one change?</p>
|
||
<div class="src">Refactoring · Clean Architecture · Pragmatic · SE@Google</div>
|
||
</div>
|
||
<div class="risk">
|
||
<span class="code">R3</span>
|
||
<h3>📋 <span data-en="Knowledge Duplication" data-zhtw="知識重複" data-ja="知識の重複" data-ko="지식 중복" data-es="Duplicación de conocimiento" data-zh="知识重复">Knowledge Duplication</span></h3>
|
||
<p data-en="Is the same decision expressed in multiple places?" data-zhtw="同一個決策是否散落在多處表達?" data-ja="同じ決定が複数の場所で表現されていないか?" data-ko="같은 결정이 여러 곳에서 표현되고 있는가?" data-es="¿La misma decisión se expresa en varios lugares?" data-zh="同一个决策是否散落在多处表达?">Is the same decision expressed in multiple places?</p>
|
||
<div class="src">Pragmatic · Refactoring · DDD</div>
|
||
</div>
|
||
<div class="risk">
|
||
<span class="code">R4</span>
|
||
<h3>🌀 <span data-en="Accidental Complexity" data-zhtw="偶發複雜度" data-ja="偶有的複雑性" data-ko="우발적 복잡성" data-es="Complejidad accidental" data-zh="偶发复杂度">Accidental Complexity</span></h3>
|
||
<p data-en="Is the code more complex than the problem itself?" data-zhtw="程式碼是否比問題本身更複雜?" data-ja="コードは問題そのものより複雑になっていないか?" data-ko="코드가 문제 자체보다 더 복잡한가?" data-es="¿El código es más complejo que el propio problema?" data-zh="代码是否比问题本身更复杂?">Is the code more complex than the problem itself?</p>
|
||
<div class="src">Refactoring · Code Complete · Brooks · Philosophy of SD</div>
|
||
</div>
|
||
<div class="risk">
|
||
<span class="code">R5</span>
|
||
<h3>🏗️ <span data-en="Dependency Disorder" data-zhtw="依賴失序" data-ja="依存関係の無秩序" data-ko="의존성 무질서" data-es="Desorden de dependencias" data-zh="依赖失序">Dependency Disorder</span></h3>
|
||
<p data-en="Do dependencies flow in a consistent direction?" data-zhtw="依賴是否朝一致的方向流動?" data-ja="依存関係は一貫した方向に流れているか?" data-ko="의존성이 일관된 방향으로 흐르는가?" data-es="¿Las dependencias fluyen en una dirección consistente?" data-zh="依赖是否朝一致的方向流动?">Do dependencies flow in a consistent direction?</p>
|
||
<div class="src">Clean Architecture · Brooks · Pragmatic · SE@Google</div>
|
||
</div>
|
||
<div class="risk">
|
||
<span class="code">R6</span>
|
||
<h3>🗺️ <span data-en="Domain Model Distortion" data-zhtw="領域模型失真" data-ja="ドメインモデルの歪み" data-ko="도메인 모델 왜곡" data-es="Distorsión del modelo de dominio" data-zh="领域模型失真">Domain Model Distortion</span></h3>
|
||
<p data-en="Does the code faithfully represent the domain?" data-zhtw="程式碼是否忠實地表達了業務領域?" data-ja="コードはドメインを忠実に表現しているか?" data-ko="코드가 도메인을 충실하게 표현하는가?" data-es="¿El código representa fielmente el dominio?" data-zh="代码是否忠实地表达了业务领域?">Does the code faithfully represent the domain?</p>
|
||
<div class="src">DDD · Refactoring</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- SAMPLE -->
|
||
<section id="sample">
|
||
<div class="wrap">
|
||
<div class="section-head">
|
||
<h2 data-en="What a finding looks like" data-zhtw="一條結論長什麼樣" data-ja="指摘はこんな形" data-ko="진단은 이런 모습입니다" data-es="Cómo se ve un hallazgo" data-zh="一条结论长什么样">What a finding looks like</h2>
|
||
<p data-en="Same messy method, two of the eight findings brooks-lint produces — each one cited and actionable." data-zhtw="同一段混亂方法,brooks-lint 給出的八條結論中的兩條——每條都有出處、可執行。" data-ja="同じ雑然としたメソッドから、brooks-lint が生成する八つの指摘のうちの二つ——いずれも出典付きで実行可能です。" data-ko="같은 지저분한 메서드에서 brooks-lint가 산출하는 여덟 진단 중 둘 — 각각 출처가 있고 실행 가능합니다." data-es="El mismo método desordenado, dos de los ocho hallazgos que produce brooks-lint — cada uno citado y accionable."
|
||
data-zh="同一段混乱方法,brooks-lint 给出的八条结论中的两条——每条都有出处、可执行。">Same messy method, two of the eight findings brooks-lint produces — each one cited and actionable.</p>
|
||
</div>
|
||
<div class="sample">
|
||
<div class="score" data-en="Health Score: <b>28/100</b>" data-zhtw="健康分:<b>28/100</b>" data-ja="健全性スコア:<b>28/100</b>" data-ko="건강 점수: <b>28/100</b>" data-es="Puntuación de salud: <b>28/100</b>" data-zh="健康分:<b>28/100</b>">Health Score: <b>28/100</b></div>
|
||
<div class="summary"
|
||
data-en="This method concentrates four unrelated business responsibilities, hides a logic bug that silently suppresses email notifications, and is wide open to SQL injection." data-zhtw="這個方法把四項互不相關的業務職責堆在一起,藏著一個讓郵件通知靜默失效的邏輯 bug,並且對 SQL 注入門戶大開。" data-ja="このメソッドは無関係な四つのビジネス責務を一つに集約し、メール通知を静かに抑制するロジックバグを隠し、SQL インジェクションに対して無防備です。" data-ko="이 메서드는 서로 무관한 네 가지 비즈니스 책임을 한데 모으고, 이메일 알림을 조용히 억제하는 로직 버그를 숨기며, SQL 인젝션에 무방비로 노출되어 있습니다." data-es="Este método concentra cuatro responsabilidades de negocio no relacionadas, oculta un error lógico que suprime silenciosamente las notificaciones por correo y queda totalmente expuesto a inyección SQL."
|
||
data-zh="这个方法把四项互不相关的业务职责堆在一起,藏着一个让邮件通知静默失效的逻辑 bug,并且对 SQL 注入门户大开。">
|
||
This method concentrates four unrelated business responsibilities, hides a logic bug that silently suppresses email notifications, and is wide open to SQL injection.
|
||
</div>
|
||
|
||
<div class="finding">
|
||
<h4><span class="dot">🔴</span> R2 — <span data-en="One method changes for four unrelated reasons" data-zhtw="一個方法因四個無關原因而改動" data-ja="一つのメソッドが四つの無関係な理由で変更される" data-ko="한 메서드가 네 가지 무관한 이유로 변경됨" data-es="Un método cambia por cuatro razones no relacionadas" data-zh="一个方法因四个无关原因而改动">One method changes for four unrelated reasons</span></h4>
|
||
<div class="row"><b data-en="Symptom:" data-zhtw="症狀:" data-ja="症状:" data-ko="증상:" data-es="Síntoma:" data-zh="症状:">Symptom:</b>
|
||
<span data-en="update_profile does field updates, email notifications, loyalty recalculation, and cache invalidation in one body." data-zhtw="update_profile 在一個方法主體裡同時做欄位更新、郵件通知、點數重算和快取失效。" data-ja="update_profile は、フィールド更新、メール通知、ロイヤルティの再計算、キャッシュ無効化を一つの本体で行っています。" data-ko="update_profile이 필드 업데이트, 이메일 알림, 적립 포인트 재계산, 캐시 무효화를 하나의 본문에서 수행합니다." data-es="update_profile hace actualizaciones de campos, notificaciones por correo, recálculo de fidelidad e invalidación de caché en un solo cuerpo."
|
||
data-zh="update_profile 在一个方法体里同时做字段更新、邮件通知、积分重算和缓存失效。">update_profile does field updates, email notifications, loyalty recalculation, and cache invalidation in one body.</span></div>
|
||
<div class="row src"><b data-en="Source:" data-zhtw="根源:" data-ja="根源:" data-ko="근원:" data-es="Origen:" data-zh="根源:">Source:</b>
|
||
<span data-en="Fowler — Refactoring — Divergent Change; Hunt & Thomas — Orthogonality" data-zhtw="Fowler — Refactoring — 發散式變更(Divergent Change);Hunt & Thomas — 正交性(Orthogonality)" data-ja="Fowler — Refactoring — 発散的変更(Divergent Change);Hunt & Thomas — 直交性(Orthogonality)" data-ko="Fowler — Refactoring — 발산적 변경(Divergent Change); Hunt & Thomas — 직교성(Orthogonality)" data-es="Fowler — Refactoring — Divergent Change (Cambio divergente); Hunt & Thomas — Orthogonality (Ortogonalidad)"
|
||
data-zh="Fowler《重构》——发散式变化;Hunt & Thomas——正交性">Fowler — Refactoring — Divergent Change; Hunt & Thomas — Orthogonality</span></div>
|
||
<div class="row"><b data-en="Consequence:" data-zhtw="後果:" data-ja="結果:" data-ko="결과:" data-es="Consecuencia:" data-zh="后果:">Consequence:</b>
|
||
<span data-en="A change to the loyalty formula risks breaking email notifications. Every edit carries regression risk across four domains." data-zhtw="改一下點數公式就可能弄壞郵件通知。每次編輯都在四個領域同時承擔回歸風險。" data-ja="ロイヤルティの計算式を変更すると、メール通知を壊すおそれがあります。すべての編集が四つのドメインにまたがる回帰リスクを背負います。" data-ko="적립 포인트 공식을 변경하면 이메일 알림이 깨질 위험이 있습니다. 모든 수정이 네 도메인에 걸친 회귀 위험을 떠안습니다." data-es="Un cambio en la fórmula de fidelidad arriesga romper las notificaciones por correo. Cada edición conlleva riesgo de regresión en cuatro dominios."
|
||
data-zh="改一下积分公式就可能弄坏邮件通知。每次编辑都在四个领域同时承担回归风险。">A change to the loyalty formula risks breaking email notifications. Every edit carries regression risk across four domains.</span></div>
|
||
<div class="row fix"><b data-en="Remedy:" data-zhtw="對策:" data-ja="対策:" data-ko="처방:" data-es="Remedio:" data-zh="修复:">Remedy:</b>
|
||
<span data-en="Extract NotificationService, LoyaltyService, UserCacheInvalidator. update_profile should orchestrate, not implement." data-zhtw="抽出 NotificationService、LoyaltyService、UserCacheInvalidator。update_profile 應當編排而非實作。" data-ja="NotificationService、LoyaltyService、UserCacheInvalidator を抽出します。update_profile は実装ではなくオーケストレーションすべきです。" data-ko="NotificationService, LoyaltyService, UserCacheInvalidator를 추출하세요. update_profile은 구현이 아니라 조율해야 합니다." data-es="Extrae NotificationService, LoyaltyService, UserCacheInvalidator. update_profile debería orquestar, no implementar."
|
||
data-zh="抽出 NotificationService、LoyaltyService、UserCacheInvalidator。update_profile 应当编排而非实现。">Extract NotificationService, LoyaltyService, UserCacheInvalidator. update_profile should orchestrate, not implement.</span></div>
|
||
</div>
|
||
|
||
<div class="finding">
|
||
<h4><span class="dot">🔴</span> R6 — <span data-en="Silent logic bug: notification never fires" data-zhtw="靜默邏輯 bug:通知永不觸發" data-ja="静かなロジックバグ:通知が決して発火しない" data-ko="조용한 로직 버그: 알림이 결코 발생하지 않음" data-es="Error lógico silencioso: la notificación nunca se dispara" data-zh="静默逻辑 bug:通知永不触发">Silent logic bug: notification never fires</span></h4>
|
||
<div class="row"><b data-en="Symptom:" data-zhtw="症狀:" data-ja="症状:" data-ko="증상:" data-es="Síntoma:" data-zh="症状:">Symptom:</b>
|
||
<span data-en="user['email'] = email runs before if user['email'] != email — the condition is always False, the code is dead." data-zhtw="user['email'] = email 在 if user['email'] != email 之前執行——條件永遠為 False,該分支是死程式碼。" data-ja="user['email'] = email が if user['email'] != email より前に実行されるため——条件は常に False で、このコードはデッドコードです。" data-ko="user['email'] = email이 if user['email'] != email보다 먼저 실행되어 — 조건이 항상 False이며, 그 코드는 죽은 코드입니다." data-es="user['email'] = email se ejecuta antes de if user['email'] != email — la condición siempre es False, el código está muerto."
|
||
data-zh="user['email'] = email 在 if user['email'] != email 之前执行——条件永远为 False,该分支是死代码。">user['email'] = email runs before if user['email'] != email — the condition is always False, the code is dead.</span></div>
|
||
<div class="row src"><b data-en="Source:" data-zhtw="根源:" data-ja="根源:" data-ko="근원:" data-es="Origen:" data-zh="根源:">Source:</b>
|
||
<span data-en="McConnell — Code Complete — Ch. 17: Unusual Control Structures" data-zhtw="McConnell — Code Complete — 第 17 章:非常規控制結構" data-ja="McConnell — Code Complete — 第 17 章:特殊な制御構造" data-ko="McConnell — Code Complete — 17장: 비정상적인 제어 구조" data-es="McConnell — Code Complete — Cap. 17: Estructuras de control inusuales"
|
||
data-zh="McConnell《代码大全》——第 17 章:非常规控制结构">McConnell — Code Complete — Ch. 17: Unusual Control Structures</span></div>
|
||
<div class="row"><b data-en="Consequence:" data-zhtw="後果:" data-ja="結果:" data-ko="결과:" data-es="Consecuencia:" data-zh="后果:">Consequence:</b>
|
||
<span data-en="Users are never notified when their email changes. A business rule is silently violated while the system looks fine." data-zhtw="使用者改信箱時永遠收不到通知。系統看似正常,業務規則卻被悄悄違反。" data-ja="ユーザーはメールアドレスを変更しても決して通知されません。システムは正常に見えながら、ビジネスルールが静かに破られています。" data-ko="사용자가 이메일을 변경해도 결코 알림을 받지 못합니다. 시스템은 정상으로 보이지만 비즈니스 규칙이 조용히 위반됩니다." data-es="Los usuarios nunca son notificados cuando cambia su correo. Una regla de negocio se viola silenciosamente mientras el sistema parece estar bien."
|
||
data-zh="用户改邮箱时永远收不到通知。系统看似正常,业务规则却被悄悄违反。">Users are never notified when their email changes. A business rule is silently violated while the system looks fine.</span></div>
|
||
<div class="row fix"><b data-en="Remedy:" data-zhtw="對策:" data-ja="対策:" data-ko="처방:" data-es="Remedio:" data-zh="修复:">Remedy:</b>
|
||
<span data-en="Capture old_email before any mutation. Compare against old_email, not the already-overwritten value." data-zhtw="在任何修改前先捕獲 old_email,與 old_email 比較,而非已被覆寫的值。" data-ja="変更の前に old_email を捕捉します。すでに上書きされた値ではなく old_email と比較してください。" data-ko="어떤 변경보다 먼저 old_email을 포착하세요. 이미 덮어쓴 값이 아니라 old_email과 비교하세요." data-es="Captura old_email antes de cualquier mutación. Compara contra old_email, no contra el valor ya sobrescrito."
|
||
data-zh="在任何修改前先捕获 old_email,与 old_email 比较,而非已被覆盖的值。">Capture old_email before any mutation. Compare against old_email, not the already-overwritten value.</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- BENCHMARK -->
|
||
<section id="benchmark" class="alt">
|
||
<div class="wrap">
|
||
<div class="section-head">
|
||
<h2 data-en="Consistency is the point" data-zhtw="一致性才是重點" data-ja="一貫性こそが肝心" data-ko="일관성이 핵심입니다" data-es="La consistencia es lo que importa" data-zh="一致性才是重点">Consistency is the point</h2>
|
||
<p data-en="Tested across PR review, architecture audit, and tech debt scenarios. The gap isn't what Claude can find — it's what it finds every single time, with evidence." data-zhtw="在 PR 審查、架構審計、技術債三類場景上測試。差距不在於 Claude 能找到什麼,而在於它能否每一次都帶著證據找到。" data-ja="PR レビュー、アーキテクチャ監査、技術的負債のシナリオで検証しました。差は Claude が何を見つけられるかではなく——毎回、証拠とともに何を見つけるかにあります。" data-ko="PR 리뷰, 아키텍처 감사, 기술 부채 시나리오에서 테스트했습니다. 격차는 Claude가 무엇을 찾을 수 있느냐가 아니라 — 매번 증거와 함께 무엇을 찾아내느냐에 있습니다." data-es="Probado en escenarios de revisión de PR, auditoría de arquitectura y deuda técnica. La diferencia no es lo que Claude puede encontrar, sino lo que encuentra cada vez, con evidencia."
|
||
data-zh="在 PR 审查、架构审计、技术债三类场景上测试。差距不在于 Claude 能找到什么,而在于它能否每一次都带着证据找到。">Tested across PR review, architecture audit, and tech debt scenarios. The gap isn't what Claude can find — it's what it finds every single time, with evidence.</p>
|
||
</div>
|
||
<div class="table-wrap">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th data-en="Criterion" data-zhtw="評判標準" data-ja="評価基準" data-ko="평가 기준" data-es="Criterio" data-zh="评判标准">Criterion</th>
|
||
<th class="c">brooks-lint</th>
|
||
<th class="c" data-en="Claude alone" data-zhtw="純 Claude" data-ja="Claude 単体" data-ko="Claude 단독" data-es="Claude solo" data-zh="纯 Claude">Claude alone</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr><td data-en="Structured Symptom→Source→Consequence→Remedy" data-zhtw="結構化 症狀→根源→後果→對策" data-ja="構造化された 症状→根源→結果→対策" data-ko="구조화된 증상→근원→결과→처방" data-es="Síntoma→Origen→Consecuencia→Remedio estructurado" data-zh="结构化 症状→根源→后果→修复">Structured Symptom→Source→Consequence→Remedy</td><td class="c yes">100%</td><td class="c no">0%</td></tr>
|
||
<tr><td data-en="Book citation per finding" data-zhtw="每條結論附書目出處" data-ja="指摘ごとの書籍出典" data-ko="진단마다 도서 출처" data-es="Cita de libro por hallazgo" data-zh="每条结论附书目出处">Book citation per finding</td><td class="c yes">100%</td><td class="c no">0%</td></tr>
|
||
<tr><td data-en="Consistent severity labels 🔴🟡🟢" data-zhtw="一致的嚴重度標籤 🔴🟡🟢" data-ja="一貫した重大度ラベル 🔴🟡🟢" data-ko="일관된 심각도 라벨 🔴🟡🟢" data-es="Etiquetas de severidad consistentes 🔴🟡🟢" data-zh="一致的严重度标签 🔴🟡🟢">Consistent severity labels 🔴🟡🟢</td><td class="c yes">100%</td><td class="c no">0%</td></tr>
|
||
<tr><td data-en="Health Score (0–100)" data-zhtw="健康分(0–100)" data-ja="健全性スコア(0〜100)" data-ko="건강 점수(0–100)" data-es="Puntuación de salud (0–100)" data-zh="健康分(0–100)">Health Score (0–100)</td><td class="c yes">100%</td><td class="c no">0%</td></tr>
|
||
<tr><td data-en="Overall pass rate" data-zhtw="總體通過率" data-ja="総合合格率" data-ko="전체 통과율" data-es="Tasa de aprobación global" data-zh="总体通过率">Overall pass rate</td><td class="c">94%</td><td class="c">16%</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- BOOKS -->
|
||
<section>
|
||
<div class="wrap">
|
||
<div class="section-head">
|
||
<h2 data-en="Standing on twelve giants" data-zhtw="站在十二位巨人的肩上" data-ja="十二人の巨人の肩の上に" data-ko="열두 거인의 어깨 위에서" data-es="Sobre los hombros de doce gigantes" data-zh="站在十二位巨人的肩上">Standing on twelve giants</h2>
|
||
<p data-en="The decay risks are our synthesis of their ideas, applied to modern code quality." data-zhtw="這些衰退風險是我們對他們思想的綜合,應用於現代程式碼品質評估。" data-ja="これらの劣化リスクは、彼らの思想を統合し、現代のコード品質に適用したものです。" data-ko="이 쇠퇴 위험들은 그들의 사상을 종합하여 현대 코드 품질에 적용한 것입니다." data-es="Los riesgos de deterioro son nuestra síntesis de sus ideas, aplicada a la calidad del código moderno."
|
||
data-zh="这些腐化风险是我们对他们思想的综合,应用于现代代码质量评估。">The decay risks are our synthesis of their ideas, applied to modern code quality.</p>
|
||
</div>
|
||
<div class="books">
|
||
<span class="book-chip"><b>The Mythical Man-Month</b> · <span>Brooks</span></span>
|
||
<span class="book-chip"><b>Code Complete</b> · <span>McConnell</span></span>
|
||
<span class="book-chip"><b>Refactoring</b> · <span>Fowler</span></span>
|
||
<span class="book-chip"><b>Clean Architecture</b> · <span>Martin</span></span>
|
||
<span class="book-chip"><b>The Pragmatic Programmer</b> · <span>Hunt & Thomas</span></span>
|
||
<span class="book-chip"><b>Domain-Driven Design</b> · <span>Evans</span></span>
|
||
<span class="book-chip"><b>A Philosophy of Software Design</b> · <span>Ousterhout</span></span>
|
||
<span class="book-chip"><b>Software Engineering at Google</b> · <span>Winters et al.</span></span>
|
||
<span class="book-chip"><b>The Art of Unit Testing</b> · <span>Osherove</span></span>
|
||
<span class="book-chip"><b>How Google Tests Software</b> · <span>Whittaker et al.</span></span>
|
||
<span class="book-chip"><b>Working Effectively with Legacy Code</b> · <span>Feathers</span></span>
|
||
<span class="book-chip"><b>xUnit Test Patterns</b> · <span>Meszaros</span></span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- INSTALL -->
|
||
<section id="install" class="alt">
|
||
<div class="wrap">
|
||
<div class="section-head">
|
||
<h2 data-en="Get started in seconds" data-zhtw="幾秒鐘即可上手" data-ja="数秒で始められます" data-ko="몇 초 만에 시작하세요" data-es="Empieza en segundos" data-zh="几秒钟即可上手">Get started in seconds</h2>
|
||
<p data-en="Pick your tool. Then just ask it to review your code, audit your architecture, or assess tech debt." data-zhtw="選擇你的工具,然後讓它審查程式碼、審計架構或評估技術債即可。" data-ja="ツールを選び、あとはコードのレビュー、アーキテクチャの監査、技術的負債の評価を頼むだけです。" data-ko="도구를 고르세요. 그런 다음 코드 리뷰, 아키텍처 감사, 기술 부채 평가를 요청하기만 하면 됩니다." data-es="Elige tu herramienta. Luego solo pídele que revise tu código, audite tu arquitectura o evalúe la deuda técnica."
|
||
data-zh="选择你的工具,然后让它审查代码、审计架构或评估技术债即可。">Pick your tool. Then just ask it to review your code, audit your architecture, or assess tech debt.</p>
|
||
</div>
|
||
<div class="install-grid">
|
||
<div class="install-label">Claude Code</div>
|
||
<div class="code-block">
|
||
<button class="copy-btn" data-copy="/plugin marketplace add hyhmrright/brooks-lint
|
||
/plugin install brooks-lint@brooks-lint-marketplace">Copy</button><span class="cmt"># add the marketplace, then install</span>
|
||
<span class="tok">/plugin</span> marketplace add hyhmrright/brooks-lint
|
||
<span class="tok">/plugin</span> install brooks-lint@brooks-lint-marketplace</div>
|
||
|
||
<div class="install-label">Gemini CLI</div>
|
||
<div class="code-block">
|
||
<button class="copy-btn" data-copy="/extensions install https://github.com/hyhmrright/brooks-lint">Copy</button><span class="tok">/extensions</span> install https://github.com/hyhmrright/brooks-lint</div>
|
||
|
||
<div class="install-label">Codex CLI</div>
|
||
<div class="code-block">
|
||
<button class="copy-btn" data-copy="Install the brooks-lint skill from hyhmrright/brooks-lint">Copy</button><span class="cmt"># just say this in a Codex session</span>
|
||
Install the brooks-lint skill from hyhmrright/brooks-lint</div>
|
||
|
||
<div class="install-label" data-en="Then, in any session:" data-zhtw="然後,在任意工作階段裡:" data-ja="そして、任意のセッションで:" data-ko="그런 다음, 어떤 세션에서든:" data-es="Luego, en cualquier sesión:" data-zh="然后,在任意会话里:">Then, in any session:</div>
|
||
<div class="code-block">
|
||
<button class="copy-btn" data-copy="/brooks-review">Copy</button><span class="tok">/brooks-review</span> <span class="cmt"># or /brooks-audit · /brooks-debt · /brooks-test · /brooks-health · /brooks-sweep</span></div>
|
||
</div>
|
||
<div style="text-align:center; margin-top:34px;">
|
||
<a class="btn btn-primary" href="https://github.com/hyhmrright/brooks-lint" target="_blank" rel="noopener" data-en="Star on GitHub ⭐" data-zhtw="去 GitHub 點個 Star ⭐" data-ja="GitHub でスターを ⭐" data-ko="GitHub에서 Star 누르기 ⭐" data-es="Dale una estrella en GitHub ⭐" data-zh="去 GitHub 点个 Star ⭐">Star on GitHub ⭐</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
|
||
<footer>
|
||
<div class="wrap foot-in">
|
||
<div class="foot-links">
|
||
<a href="https://github.com/hyhmrright/brooks-lint" target="_blank" rel="noopener">GitHub</a>
|
||
<a href="gallery.html" data-en="Gallery" data-zhtw="範例展示" data-ja="ギャラリー" data-ko="갤러리" data-es="Galería" data-zh="示例画廊">Gallery</a>
|
||
<a href="guide.html" data-en="Decay Risk Guide" data-zhtw="衰退風險指南" data-ja="劣化リスクガイド" data-ko="쇠퇴 위험 가이드" data-es="Guía de riesgos de deterioro" data-zh="腐化风险指南">Decay Risk Guide</a>
|
||
<a href="https://github.com/hyhmrright/brooks-lint/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener" data-en="Contributing" data-zhtw="參與貢獻" data-ja="コントリビュート" data-ko="기여하기" data-es="Contribuir" data-zh="参与贡献">Contributing</a>
|
||
<a href="https://github.com/hyhmrright/brooks-lint/blob/main/CHANGELOG.md" target="_blank" rel="noopener" data-en="Changelog" data-zhtw="更新日誌" data-ja="変更履歴" data-ko="변경 로그" data-es="Registro de cambios" data-zh="更新日志">Changelog</a>
|
||
</div>
|
||
<div class="foot-note" data-en="MIT License — Built by hyhmrright" data-zhtw="MIT 授權 — 由 hyhmrright 打造" data-ja="MIT ライセンス — hyhmrright が構築" data-ko="MIT 라이선스 — hyhmrright 제작" data-es="Licencia MIT — Creado por hyhmrright" data-zh="MIT 许可证 — 由 hyhmrright 构建">MIT License — Built by hyhmrright</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<script>
|
||
(function () {
|
||
var STORE = "brooks-lint-lang";
|
||
var HTML_LANG = { en: "en", zh: "zh-CN", zhtw: "zh-TW", ja: "ja", ko: "ko", es: "es" };
|
||
function apply(lang) {
|
||
document.documentElement.lang = HTML_LANG[lang] || "en";
|
||
document.querySelectorAll("[data-en]").forEach(function (el) {
|
||
var v = el.getAttribute("data-" + lang);
|
||
if (v != null) el.innerHTML = v;
|
||
});
|
||
document.querySelectorAll("[data-src-en]").forEach(function (el) {
|
||
var s = el.getAttribute("data-src-" + lang);
|
||
if (s != null) el.setAttribute("src", s);
|
||
});
|
||
document.querySelectorAll(".lang-toggle button").forEach(function (b) {
|
||
b.classList.toggle("active", b.getAttribute("data-set-lang") === lang);
|
||
});
|
||
try { localStorage.setItem(STORE, lang); } catch (e) {}
|
||
}
|
||
document.querySelectorAll("[data-set-lang]").forEach(function (b) {
|
||
b.addEventListener("click", function () { apply(b.getAttribute("data-set-lang")); });
|
||
});
|
||
var saved;
|
||
try { saved = localStorage.getItem(STORE); } catch (e) {}
|
||
if (!saved) {
|
||
var nav = (navigator.language || "").toLowerCase();
|
||
saved = (nav.indexOf("zh-tw") === 0 || nav.indexOf("zh-hant") === 0
|
||
|| nav.indexOf("zh-hk") === 0 || nav.indexOf("zh-mo") === 0) ? "zhtw"
|
||
: nav.indexOf("zh") === 0 ? "zh"
|
||
: nav.indexOf("ja") === 0 ? "ja"
|
||
: nav.indexOf("ko") === 0 ? "ko"
|
||
: nav.indexOf("es") === 0 ? "es"
|
||
: "en";
|
||
}
|
||
apply(saved);
|
||
|
||
// copy buttons
|
||
document.querySelectorAll(".copy-btn").forEach(function (btn) {
|
||
btn.addEventListener("click", function () {
|
||
var text = btn.getAttribute("data-copy");
|
||
navigator.clipboard.writeText(text).then(function () {
|
||
var prev = btn.textContent;
|
||
btn.textContent = "✓";
|
||
setTimeout(function () { btn.textContent = prev; }, 1200);
|
||
});
|
||
});
|
||
});
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|