<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark light">
<title>CheetahString 3.1 架构与性能复审 · 95/100</title>
<style>
:root {
--bg: #0a0e11;
--panel: #10171b;
--panel-2: #151e23;
--ink: #f2efe5;
--muted: #9da9a6;
--line: #29363a;
--accent: #ff6a3d;
--cyan: #6ed8c7;
--amber: #efc56c;
--red: #ff746c;
--green: #83d38c;
--rail: 248px;
--mono: "Cascadia Code", "SFMono-Regular", Consolas, monospace;
--sans: "Segoe UI", "Microsoft YaHei UI", "Noto Sans CJK SC", Arial, sans-serif;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
overflow-x: hidden;
background:
linear-gradient(rgba(255,255,255,.018) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,.018) 1px, transparent 1px),
var(--bg);
background-size: 36px 36px;
color: var(--ink);
font-family: var(--sans);
line-height: 1.7;
}
a { color: var(--cyan); text-decoration: none; }
a:hover { text-decoration: underline; }
code, .mono { font-family: var(--mono); }
code { color: #c9eee7; font-size: .92em; }
.rail {
position: fixed;
inset: 0 auto 0 0;
width: var(--rail);
padding: 28px 22px;
border-right: 1px solid var(--line);
background: rgba(10,14,17,.94);
backdrop-filter: blur(12px);
z-index: 20;
display: flex;
flex-direction: column;
}
.brand { letter-spacing: .12em; text-transform: uppercase; font: 700 13px var(--mono); }
.brand span { color: var(--accent); }
.rail .commit { margin-top: 8px; color: var(--muted); font: 12px var(--mono); }
nav { margin-top: 34px; display: grid; gap: 6px; }
nav a {
color: var(--muted);
padding: 7px 10px;
border-left: 2px solid transparent;
font-size: 13px;
}
nav a.active, nav a:hover {
color: var(--ink);
border-left-color: var(--accent);
text-decoration: none;
background: rgba(255,106,61,.08);
}
.rail-foot { margin-top: auto; color: var(--muted); font-size: 11px; }
main { margin-left: var(--rail); }
.wrap { width: min(1160px, calc(100vw - var(--rail) - 64px)); margin: 0 auto; }
.hero {
min-height: 82vh;
display: grid;
align-items: center;
border-bottom: 1px solid var(--line);
position: relative;
overflow: hidden;
}
.hero::after {
content: "AUDIT / 2026";
position: absolute;
right: -30px;
bottom: -48px;
font: 900 clamp(70px, 11vw, 170px)/1 var(--mono);
color: rgba(255,255,255,.025);
pointer-events: none;
}
.eyebrow { color: var(--accent); font: 700 12px var(--mono); letter-spacing: .16em; text-transform: uppercase; }
h1 { margin: 14px 0 18px; max-width: 900px; font-size: clamp(44px, 6.4vw, 88px); line-height: 1.02; letter-spacing: -.045em; }
.lede { max-width: 790px; font-size: clamp(17px, 2vw, 22px); color: #c4cecb; }
.lede, .card, .verdict, .risk, td { overflow-wrap: anywhere; }
.hero-grid { display: grid; grid-template-columns: 1fr 260px; gap: 56px; align-items: center; }
.score-ring {
width: 230px; aspect-ratio: 1;
border-radius: 50%;
display: grid; place-items: center;
background: conic-gradient(var(--green) 0 95%, #253136 95% 100%);
position: relative;
box-shadow: 0 0 80px rgba(255,106,61,.12);
}
.score-ring::before { content: ""; position: absolute; inset: 13px; border-radius: 50%; background: var(--bg); }
.score-value { position: relative; text-align: center; }
.score-value strong { display: block; font: 800 70px/.9 var(--mono); }
.score-value span { color: var(--muted); font: 12px var(--mono); }
.meta-strip { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 34px; }
.chip { border: 1px solid var(--line); padding: 7px 10px; color: var(--muted); font: 12px var(--mono); background: rgba(255,255,255,.02); }
.chip.good { border-color: rgba(131,211,140,.45); color: var(--green); }
.chip.warn { border-color: rgba(239,197,108,.45); color: var(--amber); }
.chip.bad { border-color: rgba(255,116,108,.5); color: var(--red); }
section { padding: 88px 0; border-bottom: 1px solid var(--line); scroll-margin-top: 10px; }
.section-head { display: grid; grid-template-columns: 120px 1fr; gap: 28px; margin-bottom: 38px; }
.section-no { color: var(--accent); font: 700 13px var(--mono); letter-spacing: .12em; }
h2 { margin: 0; font-size: clamp(31px, 4vw, 52px); letter-spacing: -.035em; line-height: 1.08; }
h3 { margin: 0 0 12px; font-size: 20px; }
h4 { margin: 0 0 8px; font-size: 15px; }
.sub { color: var(--muted); max-width: 820px; margin-top: 12px; }
.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 16px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 16px; }
.card { background: var(--panel); border: 1px solid var(--line); padding: 22px; }
.card p:last-child { margin-bottom: 0; }
.kicker { color: var(--muted); font: 11px var(--mono); letter-spacing: .08em; text-transform: uppercase; }
.metric { margin-top: 5px; font: 750 34px/1.1 var(--mono); letter-spacing: -.04em; }
.metric small { color: var(--muted); font-size: 13px; letter-spacing: 0; }
.good-text { color: var(--green); }
.warn-text { color: var(--amber); }
.bad-text { color: var(--red); }
.verdict {
margin: 30px 0;
padding: 22px 24px;
border-left: 4px solid var(--accent);
background: linear-gradient(90deg, rgba(255,106,61,.11), transparent);
font-size: 18px;
}
.verdict strong { color: #fff; }
.score-list { display: grid; gap: 18px; }
.score-row { display: grid; grid-template-columns: 230px 1fr 70px; gap: 18px; align-items: center; }
.score-row .label small { display: block; color: var(--muted); }
.track { height: 10px; background: #222e32; overflow: hidden; }
.fill { height: 100%; width: var(--pct); background: linear-gradient(90deg, var(--cyan), var(--accent)); }
.points { text-align: right; font: 700 17px var(--mono); }
.score-note { margin-top: 28px; color: var(--muted); font-size: 13px; }
.arch-map { background: var(--panel); border: 1px solid var(--line); padding: 28px; overflow-x: auto; }
.arch-lanes { min-width: 820px; display: grid; grid-template-columns: 1.05fr 40px 1.1fr 40px 1.25fr; gap: 12px; align-items: stretch; }
.node { border: 1px solid #35464b; background: #121b20; padding: 18px; display: grid; align-content: center; }
.node strong { display: block; font-family: var(--mono); }
.node span { color: var(--muted); font-size: 12px; }
.node.inline { border-top: 3px solid var(--cyan); }
.node.static { border-top: 3px solid var(--amber); }
.node.shared { border-top: 3px solid var(--accent); }
.arrow { display: grid; place-items: center; color: var(--muted); font: 24px var(--mono); }
.stack { display: grid; gap: 10px; }
.callout { border: 1px solid var(--line); padding: 18px 20px; margin: 18px 0; background: rgba(255,255,255,.018); }
.callout.danger { border-left: 4px solid var(--red); }
.callout.warning { border-left: 4px solid var(--amber); }
.callout.success { border-left: 4px solid var(--green); }
.table-wrap { overflow-x: auto; border: 1px solid var(--line); background: var(--panel); }
table { width: 100%; border-collapse: collapse; min-width: 760px; }
th, td { padding: 13px 15px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
th { color: var(--muted); font: 700 11px var(--mono); letter-spacing: .08em; text-transform: uppercase; background: #11191d; }
td.num { text-align: right; font-family: var(--mono); white-space: nowrap; }
tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: rgba(110,216,199,.035); }
.bars { display: grid; gap: 13px; }
.bar-row { display: grid; grid-template-columns: 130px 1fr 105px; gap: 14px; align-items: center; }
.bar-label { font: 12px var(--mono); }
.bar-track { height: 20px; background: #202b2f; position: relative; }
.bar { height: 100%; width: var(--w); min-width: 2px; background: var(--cyan); }
.bar.orange { background: var(--accent); }
.bar.amber { background: var(--amber); }
.bar-value { text-align: right; color: var(--muted); font: 12px var(--mono); }
.chart-note { color: var(--muted); font-size: 12px; margin-top: 12px; }
.risk { display: grid; grid-template-columns: 66px 1fr 150px; gap: 18px; padding: 22px 0; border-top: 1px solid var(--line); }
.risk:last-child { border-bottom: 1px solid var(--line); }
.sev { height: fit-content; padding: 5px 8px; text-align: center; font: 800 12px var(--mono); border: 1px solid currentColor; }
.sev.p0 { color: var(--red); }
.sev.p1 { color: var(--amber); }
.sev.p2 { color: var(--cyan); }
.risk p { margin: 5px 0 0; color: var(--muted); }
.risk .impact { color: var(--muted); font: 12px var(--mono); }
.roadmap { counter-reset: item; display: grid; gap: 2px; }
.road-step { counter-increment: item; display: grid; grid-template-columns: 74px 1fr; gap: 18px; padding: 24px; background: var(--panel); border: 1px solid var(--line); }
.road-step::before { content: "0" counter(item); color: var(--accent); font: 800 28px var(--mono); }
.road-step ul { margin: 10px 0 0; padding-left: 20px; color: var(--muted); }
details { border: 1px solid var(--line); background: var(--panel); margin: 10px 0; }
summary { cursor: pointer; padding: 15px 18px; font-weight: 650; }
details > div { padding: 0 18px 18px; color: var(--muted); }
.cmd { display: block; margin: 8px 0; padding: 10px 12px; background: #080c0e; border: 1px solid #243035; overflow-x: auto; color: #c8e8e2; font: 12px/1.5 var(--mono); white-space: pre; }
.status { display: inline-block; min-width: 56px; padding: 3px 6px; text-align: center; font: 800 11px var(--mono); }
.status.pass { color: var(--green); border: 1px solid rgba(131,211,140,.45); }
.status.fail { color: var(--red); border: 1px solid rgba(255,116,108,.5); }
.status.limit { color: var(--amber); border: 1px solid rgba(239,197,108,.45); }
.foot { padding: 44px 0 70px; color: var(--muted); font-size: 12px; }
.foot-line { display: flex; justify-content: space-between; gap: 20px; border-top: 1px solid var(--line); padding-top: 20px; }
.no-break { white-space: nowrap; }
.print-btn { border: 1px solid var(--line); background: var(--panel); color: var(--ink); padding: 8px 12px; cursor: pointer; font: 12px var(--mono); }
.print-btn:hover { border-color: var(--accent); }
@media (max-width: 980px) {
:root { --rail: 0px; }
.rail { position: sticky; width: 100%; max-width: 100vw; height: auto; padding: 12px 18px; border-right: 0; border-bottom: 1px solid var(--line); flex-direction: row; align-items: center; overflow: hidden; }
.rail .commit, .rail-foot { display: none; }
nav { margin: 0 0 0 auto; width: 100%; min-width: 0; display: flex; overflow-x: auto; }
nav a { white-space: nowrap; border-left: 0; border-bottom: 2px solid transparent; padding: 7px 8px; }
nav a.active { border-left-color: transparent; border-bottom-color: var(--accent); }
main { margin-left: 0; width: 100%; max-width: 100vw; }
main, .hero-grid, .card, .section-head > * { min-width: 0; }
.wrap { width: min(100% - 32px, 1160px); }
.hero-grid { grid-template-columns: 1fr; padding: 70px 0; }
.score-ring { width: 180px; }
.grid-3 { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
.brand { display: none; }
nav { margin-left: 0; }
.hero { min-height: auto; }
.hero-grid { gap: 34px; }
.section-head { grid-template-columns: 1fr; gap: 6px; }
section { padding: 64px 0; }
.grid-2 { grid-template-columns: 1fr; }
.score-row { grid-template-columns: 1fr 58px; gap: 8px; }
.score-row .track { grid-column: 1 / -1; grid-row: 2; }
.points { grid-column: 2; grid-row: 1; }
.risk { grid-template-columns: 58px 1fr; }
.risk .impact { grid-column: 2; }
.bar-row { grid-template-columns: 90px 1fr; }
.bar-value { grid-column: 2; text-align: left; }
}
@media print {
:root { --bg:#fff; --panel:#fff; --panel-2:#f5f5f2; --ink:#171b1d; --muted:#596366; --line:#c8ced0; }
body { background: #fff; }
.rail, .print-btn { display: none; }
main { margin: 0; }
.wrap { width: 94%; }
.hero { min-height: auto; padding: 35px 0; }
section { padding: 35px 0; break-inside: avoid; }
.score-ring::before { background:#fff; }
a, code { color:#075d5b; }
}
</style>
</head>
<body>
<aside class="rail">
<div class="brand">Cheetah<span>/Audit</span></div>
<div class="commit">300b313 · v3.1.0</div>
<nav aria-label="报告目录">
<a href="#summary">执行摘要</a>
<a href="#score">评分账本</a>
<a href="#architecture">架构</a>
<a href="#performance">性能</a>
<a href="#safety">安全与正确性</a>
<a href="#engineering">工程证据</a>
<a href="#roadmap">改进路线</a>
<a href="#method">方法与证据</a>
</nav>
<div class="rail-foot">合并后复审<br>2026-08-12 · Asia/Shanghai</div>
</aside>
<main>
<header class="hero" id="summary">
<div class="wrap hero-grid">
<div>
<div class="eyebrow">Architecture × Performance × Evidence</div>
<h1>CheetahString<br>深度审计</h1>
<p class="lede">3.1 已把最初审计中的安全、布局、MSRV、分配、API 与发布证据缺口逐项闭合:保持 23B SSO 与 <code>Arc<str></code> 克隆语义,同时用安全 Rust niche 将对象压到 24B。它仍不是所有写入型负载上的 <code>String</code> 替代品,但已具备可验证的发布级工程闭环。</p>
<div class="meta-strip">
<span class="chip good">203 / 203 Rust tests</span>
<span class="chip good">24B object + 23B SSO</span>
<span class="chip good">61 Miri tests</span>
<span class="chip good">Rust 1.95 matrix: PASS</span>
<span class="chip good">stable API gate: PASS</span>
</div>
</div>
<div class="score-ring" aria-label="综合评分 95 分">
<div class="score-value"><strong>95</strong><span>/ 100 · 综合评分</span></div>
</div>
</div>
</header>
<section>
<div class="wrap">
<div class="section-head">
<div class="section-no">00 / VERDICT</div>
<div><h2>结论先行</h2><p class="sub">评分对象是合并后的完整 3.1 仓库。置信度:高;布局、分配、MSRV 与 API 结论由门禁证明,Criterion 时序仍只作为本机诊断。</p></div>
</div>
<div class="verdict"><strong>建议使用:</strong>协议字段、路由键、缓存键等“构造一次、读取和克隆很多次”的 UTF-8 值;已有长 <code>Arc<str></code> 可零拷贝接管。<br><strong>保留 <code>String</code>:</strong>持续追加、频繁变换、一次性消费,或必须保留 spare capacity 的写入路径。</div>
<div class="grid-3">
<article class="card"><div class="kicker">核心架构</div><div class="metric good-text">成熟</div><p>Inline / Static / Shared 三态、Builder 写入边界、byte/text 所有权与私有 pattern dispatch 相互一致;兼容 shim 不参与内部实现。</p></article>
<article class="card"><div class="kicker">性能画像</div><div class="metric good-text">可预测</div><p>24B 槽位与 <code>String</code> 等大;长 clone、<code>Arc<str></code> adoption、char 与短 concat 均为 0 allocation。长 freeze/transform 仍需复制。</p></article>
<article class="card"><div class="kicker">发布成熟度</div><div class="metric good-text">闭环</div><p>5 套工作流覆盖 MSRV、文档、Miri、fuzz build、audit、性能和 semver;发布在校验与 digest 检查后才创建 tag。</p></article>
</div>
</div>
</section>
<section id="score">
<div class="wrap">
<div class="section-head">
<div class="section-no">01 / SCORE</div>
<div><h2>100 分评分账本</h2><p class="sub">权重向架构与性能倾斜(合计 55 分);每一处扣分都能落到源码、命令结果或本机测量。</p></div>
</div>
<div class="score-list card">
<div class="score-row"><div class="label"><strong>核心架构与 API</strong><small>三态模型、模块职责、3.1 兼容面</small></div><div class="track"><div class="fill" style="--pct:96%"></div></div><div class="points">24/25</div></div>
<div class="score-row"><div class="label"><strong>运行时性能</strong><small>克隆、搜索、构造、真实形状负载</small></div><div class="track"><div class="fill" style="--pct:93.3%"></div></div><div class="points">28/30</div></div>
<div class="score-row"><div class="label"><strong>内存与分配</strong><small>24B 对象、23B SSO、freeze、共享边界</small></div><div class="track"><div class="fill" style="--pct:100%"></div></div><div class="points">15/15</div></div>
<div class="score-row"><div class="label"><strong>正确性与安全</strong><small>测试、Miri、unsafe、feature 风险</small></div><div class="track"><div class="fill" style="--pct:93.3%"></div></div><div class="points">14/15</div></div>
<div class="score-row"><div class="label"><strong>工程证据与发布</strong><small>CI、MSRV、文档、可复现性、供应链</small></div><div class="track"><div class="fill" style="--pct:93.3%"></div></div><div class="points">14/15</div></div>
</div>
<p class="score-note">总分 <strong>95/100</strong>。仍使用最初报告的独立 rubric:退役存在 UB 的实验 packed API、兼容 shim 与既有 Error 聚合模型合计扣 1 分;长 transform/substring/freeze 的复制成本扣 2 分;CI 只编译 fuzz target、尚无持续限时 fuzz 执行扣 1 分;跨机器时序没有固定 CPU 阻断门禁再扣 1 分。评分不依赖已删除的旧自评分脚本。</p>
</div>
</section>
<section id="architecture">
<div class="wrap">
<div class="section-head">
<div class="section-no">02 / ARCH</div>
<div><h2>架构:用不可变性买下确定的克隆成本</h2><p class="sub">根模块是薄门面,核心类型再按 construct / convert / query / pattern / repr / traits 分层。真正的架构中心不是 SSO,而是“构造历史不能改变 clone 复杂度”。</p></div>
</div>
<div class="arch-map" aria-label="CheetahString 数据流">
<div class="arch-lanes">
<div class="stack">
<div class="node"><strong>&str / String / Arc<str> / Vec<u8></strong><span>safe bytes 先做 UTF-8 validation</span></div>
<div class="node"><strong>CheetahBuilder</strong><span>String 承担 mutation / reserve / clear</span></div>
<div class="node"><strong>&'static str</strong><span>显式 static constructor</span></div>
</div>
<div class="arrow">→</div>
<div class="stack">
<div class="node"><strong>length / ownership gate</strong><span>普通构造:≤23B inline;长值 freeze</span></div>
<div class="node"><strong>finish()</strong><span>mutable → immutable;长值复制进 Arc<str></span></div>
<div class="node"><strong>from_static_str()</strong><span>无论长度,直接选择 Static</span></div>
</div>
<div class="arrow">→</div>
<div class="stack">
<div class="node inline"><strong>Inline</strong><span>受限 len enum + [u8; 23] · 0 heap alloc</span></div>
<div class="node static"><strong>Static</strong><span>&'static str · 0 heap alloc</span></div>
<div class="node shared"><strong>Shared</strong><span>Arc<str> · clone = atomic refcount</span></div>
</div>
</div>
</div>
<div class="grid-2" style="margin-top:16px">
<article class="card"><h3>设计已闭合的部分</h3><ul><li>稳定表示只有 Inline / Static / Shared 三态,字段私有,文本语义统一。</li><li>Builder 把可变容量从 value type 剥离,避免构造历史改变 clone 复杂度。</li><li><code>From<Arc<str>></code> 对长值保留 payload pointer;短值仍 canonicalize 为 Inline。</li><li><code>lines()</code> 暴露 DoubleEnded / Clone / Fused;char 与 string split 在类型层表达能力。</li><li>pattern 查询使用私有 sealed classifier;3.1 兼容方法仅作为桥接面保留。</li><li>错误返回矩阵、静态优先级和复制边界已在 <a href="API.md"><code>API.md</code></a> 中明确。</li></ul></article>
<article class="card"><h3>仍保留的架构权衡</h3><ul><li>显式 <code>from_static_str</code> 总是 Static,而非按长度 Inline;这是记录清楚的 ownership 优先规则。</li><li><code>from(String)</code> 与 <code>finish()</code> 必须把可变 payload 冻结为 <code>Arc<str></code>,不能做到零复制。</li><li><code>substring</code> 产生独立值,不保存 shared slice 的 offset/length,因此长片段需分配复制。</li><li>3.1 为源码兼容继续保留隐藏 pattern dispatch 与 umbrella Error;内部实现已与其解耦。</li><li><code>experimental-simd</code> 的收益依操作和长度而异,保持默认关闭。</li></ul></article>
</div>
<div class="callout warning"><strong>“零分配克隆/接管”不等于“所有构造零成本”。</strong> 长 <code>Arc<str></code> adoption 为 0 allocation;长 borrowed / exact-capacity String freeze 为 1 次;spare-capacity String / Builder freeze 为 2 次。三条路径都由直接计数契约和 schema-v3 benchmark evidence 验证,而非同构推断。</div>
<h3 style="margin-top:36px">稳定复杂度模型</h3>
<div class="table-wrap"><table>
<thead><tr><th>操作</th><th>Inline / Static</th><th>Shared</th><th>架构含义</th></tr></thead>
<tbody>
<tr><td><code>clone</code></td><td>O(1),复制有界 24B / 指针</td><td>O(1),Arc 原子计数</td><td>0 allocation;长值 payload pointer 不变</td></tr>
<tr><td><code>as_str / len</code></td><td>O(1)</td><td>O(1)</td><td>一次 enum dispatch,可内联</td></tr>
<tr><td><code>from(&str)</code></td><td>O(k≤23),0 alloc</td><td>O(n),1 live allocation</td><td>长 borrowed input 复制进 Arc</td></tr>
<tr><td><code>from(Arc<str>)</code></td><td>O(k≤23),0 alloc</td><td>O(1),0 alloc</td><td>长值 ownership-preserving;pointer 不变</td></tr>
<tr><td><code>from(String) / finish</code></td><td>O(k≤23),结果 inline</td><td>O(n),1–2 allocation events</td><td>spare capacity 先 shrink/realloc</td></tr>
<tr><td><code>substring</code></td><td>O(k),复制</td><td>O(k),长结果 1 alloc</td><td>不是 shared slice</td></tr>
<tr><td><code>Add / transform</code></td><td>≤23B concat 直接栈上,0 alloc</td><td>O(n+m);长结果经 String freeze</td><td>长变换通常应先保留 String/Builder</td></tr>
</tbody>
</table></div>
</div>
</section>
<section id="performance">
<div class="wrap">
<div class="section-head">
<div class="section-no">03 / PERF</div>
<div><h2>性能:读多写少模型成立,构造边界仍需按负载取舍</h2><p class="sub">当前提交的 Criterion 本地诊断:Windows 11 / i7-11700K / rustc 1.96.1。评分只依赖可重复的布局与分配契约;未固定频率、CPU affinity 与双向 base/head 的纳秒数据只用于解释趋势。</p></div>
</div>
<div class="grid-3">
<article class="card"><div class="kicker">1 KiB clone</div><div class="metric good-text">26.49 ns</div><p><code>String</code> 为 246.10 ns,本机约 <strong>9.29×</strong>;共享长值 clone 为 O(1) 且零分配。</p></article>
<article class="card"><div class="kicker">25B borrowed construction</div><div class="metric warn-text">55.75 ns</div><p><code>String</code> 为 40.69 ns;刚越过 23B inline 边界时,本机 median 慢约 <strong>37%</strong>。</p></article>
<article class="card"><div class="kicker">10k × 25B topic insert</div><div class="metric">653.37 µs</div><p><code>String</code> 为 614.94 µs;本机 median 差约 <strong>6.3%</strong>,95% CI 重叠,判定为近似持平。</p></article>
</div>
<h3 style="margin-top:40px">克隆曲线:23B 内联是有界复制,长值是常数时间共享</h3>
<div class="grid-2">
<div class="card">
<div class="bars">
<div class="bar-row"><div class="bar-label">10B · Cheetah</div><div class="bar-track"><div class="bar" style="--w:31%"></div></div><div class="bar-value">18.28 ns</div></div>
<div class="bar-row"><div class="bar-label">10B · String</div><div class="bar-track"><div class="bar orange" style="--w:52%"></div></div><div class="bar-value">31.01 ns</div></div>
<div class="bar-row"><div class="bar-label">23B · Cheetah</div><div class="bar-track"><div class="bar" style="--w:45%"></div></div><div class="bar-value">27.25 ns</div></div>
<div class="bar-row"><div class="bar-label">23B · String</div><div class="bar-track"><div class="bar orange" style="--w:77%"></div></div><div class="bar-value">46.28 ns</div></div>
<div class="bar-row"><div class="bar-label">24B · Cheetah</div><div class="bar-track"><div class="bar" style="--w:32%"></div></div><div class="bar-value">19.14 ns</div></div>
<div class="bar-row"><div class="bar-label">24B · String</div><div class="bar-track"><div class="bar orange" style="--w:68%"></div></div><div class="bar-value">40.55 ns</div></div>
<div class="bar-row"><div class="bar-label">1KiB · Cheetah</div><div class="bar-track"><div class="bar" style="--w:11%"></div></div><div class="bar-value">26.49 ns</div></div>
<div class="bar-row"><div class="bar-label">1KiB · String</div><div class="bar-track"><div class="bar orange" style="--w:100%"></div></div><div class="bar-value">246.10 ns</div></div>
</div>
<p class="chart-note">前六条以 60 ns 为满刻度;1KiB 两条以 246.10 ns 为满刻度。精确值见右表。</p>
</div>
<div class="table-wrap"><table style="min-width:0">
<thead><tr><th>payload</th><th>Cheetah clone</th><th>String clone</th><th>判断</th></tr></thead>
<tbody>
<tr><td>10 B</td><td class="num">18.277 ns</td><td class="num">31.010 ns</td><td class="num good-text">快约 41%</td></tr>
<tr><td>23 B</td><td class="num">27.245 ns</td><td class="num">46.283 ns</td><td class="num good-text">快约 41%</td></tr>
<tr><td>24 B</td><td class="num">19.136 ns</td><td class="num">40.545 ns</td><td class="num good-text">快约 53%</td></tr>
<tr><td>100 B</td><td class="num">23.262 ns</td><td class="num">69.200 ns</td><td class="num good-text">快约 66%</td></tr>
<tr><td>1 KiB</td><td class="num">26.494 ns</td><td class="num">246.10 ns</td><td class="num good-text">9.29× 快</td></tr>
</tbody>
</table></div>
</div>
<div class="callout success"><strong>可重复证据:</strong>长值 clone 在分配计数器下为 0 allocation,且 clone 前后 payload 指针一致。短值 clone 最多复制 23B;长值只增加 <code>Arc<str></code> 的原子引用计数。</div>
<h3 style="margin-top:40px">构造与冻结:零拷贝入口已补齐,SSO 边界仍可观察</h3>
<div class="grid-2">
<article class="card"><div class="kicker">From<Arc<str>> · long</div><div class="metric good-text">0 alloc</div><p>转换复用原 payload 指针;这是调用方已有共享字符串时的真实零拷贝入口。</p></article>
<article class="card"><div class="kicker">1KiB freeze</div><div class="metric">1 / 2 alloc</div><p>exact-capacity 输入 1 次、1040B;spare-capacity 输入 2 次、2064B。写入侧仍为 O(n) 冻结。</p></article>
</div>
<div class="table-wrap" style="margin-top:16px"><table>
<thead><tr><th>borrowed input</th><th>CheetahString::from</th><th>String::from</th><th>本机判断</th></tr></thead>
<tbody>
<tr><td>23 B</td><td class="num">28.884 ns</td><td class="num">46.666 ns</td><td class="good-text">内联,快约 38%</td></tr>
<tr><td>24 B</td><td class="num">54.287 ns</td><td class="num">34.819 ns</td><td class="warn-text">进入 Shared,慢约 56%</td></tr>
<tr><td>25 B</td><td class="num">55.754 ns</td><td class="num">40.688 ns</td><td class="warn-text">慢约 37%</td></tr>
<tr><td>100 B</td><td class="num">73.848 ns</td><td class="num">70.509 ns</td><td>近似持平</td></tr>
<tr><td>1 KiB</td><td class="num">295.22 ns</td><td class="num">295.64 ns</td><td>近似持平</td></tr>
</tbody>
</table></div>
<h3 style="margin-top:40px">Schema v3:确定性分配证据</h3>
<div class="table-wrap"><table>
<thead><tr><th>操作</th><th>allocation events</th><th>allocated bytes</th><th>契约</th></tr></thead>
<tbody>
<tr><td>1KiB borrowed → Shared</td><td class="num">1</td><td class="num">1040</td><td>一次共享 backing 分配</td></tr>
<tr><td>1KiB owned exact → Shared</td><td class="num">1</td><td class="num">1040</td><td>冻结复制到最终 backing</td></tr>
<tr><td>1KiB owned spare → Shared</td><td class="num">2</td><td class="num">2064</td><td>收缩/复制成本显式可见</td></tr>
<tr><td>long <code>Arc<str></code> adoption</td><td class="num good-text">0</td><td class="num good-text">0</td><td>payload pointer reused</td></tr>
<tr><td>Shared clone / char / short concat</td><td class="num good-text">0</td><td class="num good-text">0</td><td>三个热路径均有回归门禁</td></tr>
</tbody>
</table></div>
<div class="callout success"><strong>RocketMQ 形状已接近持平。</strong>10,000 个 25B topic 插入的 median:CompactString 580.14 µs、String 614.94 µs、CheetahString 653.37 µs、Arc<str> 666.42 µs。Cheetah 比 String 慢约 6.3%,但两者 95% CI 重叠;24B 槽位消除了旧 32B 表示的密度劣势。随机 hash seed 与本机噪声仍使该结果只适合作为诊断,不作为发布硬门。</div>
<h3 style="margin-top:40px">搜索与 SIMD:代码路径保守,历史基线仅作方向性参考</h3>
<div class="grid-2">
<article class="card"><h4><code>memchr/memmem</code> + Finder</h4><p>空 needle 为 O(1),单字节走 <code>memchr</code>,多字节走 <code>memmem</code>;重复查询可复用预构建 Finder。该路径在 3.1 未改变,初始审计中 64KiB 末尾单字节诊断为 613 ns,而 <code>str::find</code> 为 36.5 µs。</p></article>
<article class="card"><h4>实验 SSE2 默认关闭</h4><p>初始诊断呈混合结果:16B equality 明显受益,但 starts_with 和部分中等长度 equality 退化。3.1 修复 Rust 1.95 编译边界但未把 SIMD 设为默认;这一决策与证据一致。</p></article>
</div>
<p class="chart-note">搜索与 SIMD 数值来自初始审计基线,不混入当前 95 分评分。启用 SIMD 前仍应按 CPU family、操作和长度校准,并保留 portable fallback。</p>
</div>
</section>
<section>
<div class="wrap">
<div class="section-head">
<div class="section-no">04 / MEMORY</div>
<div><h2>内存布局:安全 24B 表示保留完整 23B SSO</h2><p class="sub">私有的受约束长度枚举为三态表示提供安全 niche;64 位与 32 位布局快照都把 <code>CheetahString</code> 和 <code>Option<CheetahString></code> 固定在 24B,未引入整数化指针。</p></div>
</div>
<div class="grid-2">
<div class="card">
<div class="bars">
<div class="bar-row"><div class="bar-label">CheetahString</div><div class="bar-track"><div class="bar" style="--w:100%"></div></div><div class="bar-value">24 B</div></div>
<div class="bar-row"><div class="bar-label">Option<Cheetah></div><div class="bar-track"><div class="bar" style="--w:100%"></div></div><div class="bar-value">24 B</div></div>
<div class="bar-row"><div class="bar-label">String</div><div class="bar-track"><div class="bar" style="--w:100%"></div></div><div class="bar-value">24 B</div></div>
<div class="bar-row"><div class="bar-label">Arc<str></div><div class="bar-track"><div class="bar orange" style="--w:67%"></div></div><div class="bar-value">16 B</div></div>
<div class="bar-row"><div class="bar-label">&str</div><div class="bar-track"><div class="bar orange" style="--w:67%"></div></div><div class="bar-value">16 B</div></div>
</div>
</div>
<article class="card"><h3>容器级含义</h3><p>100 万个元素只算对象槽位:Cheetah 与 String 都约 <strong>22.9 MiB</strong>。相对旧 32B 表示,Cheetah 每百万元素节省约 <strong>7.6 MiB</strong>;10,000 项的确定性证据为 240,000B,对照旧表示为 320,000B。</p><p>HashMap 中 <code>(CheetahString, usize)</code> 与 <code>(String, usize)</code> 的 payload 均为 32B。这个结果同时保留 23B SSO、<code>Option</code> niche 与稳定指针 provenance。</p></article>
</div>
<p class="chart-note">来源:<a href="LAYOUT.md"><code>LAYOUT.md</code></a>、<a href="tests/layout_snapshot.rs"><code>tests/layout_snapshot.rs</code></a> 与 schema-v3 allocation evidence;CI 在原生 i686 target 上运行 32 位布局测试。</p>
</div>
</section>
<section id="safety">
<div class="wrap">
<div class="section-head">
<div class="section-no">05 / SAFETY</div>
<div><h2>安全:问题表示已退役,稳定 24B 路径通过 provenance 验证</h2><p class="sub">3.1 不再公开旧 packed 模块;兼容 feature 名仅为空操作。当前 24B 表示使用 Safe Rust 的枚举 niche,稳定 unsafe 边界集中记录并由 Miri、审计和全特性测试共同约束。</p></div>
</div>
<div class="grid-3">
<article class="card"><div class="kicker">Rust tests</div><div class="metric good-text">203/203</div><p>171 unit/integration + 32 doctests;all-features 全过。</p></article>
<article class="card"><div class="kicker">Miri matrix</div><div class="metric good-text">61 pass</div><p>lib 4、API 3、basic 47、bytes 7,覆盖三种 storage mode 与转换边界。</p></article>
<article class="card"><div class="kicker">Supply chain</div><div class="metric good-text">0 findings</div><p>74 个依赖;本地 advisory database 中无漏洞或 warning。</p></article>
</div>
<div class="risk"><div class="sev p2">P2</div><div><h3>将 fuzz 从“可构建”提升为持续执行</h3><p>Safety workflow 会编译两个稳定 fuzz target,但当前证据没有固定时长的自动 corpus 执行。字符编码和 bytes 转换边界适合增加 Linux sanitizer runner 与定时任务。</p></div><div class="impact">残余风险:输入空间<br><a href=".github/workflows/safety.yml"><code>safety.yml</code></a><br><a href="fuzz/fuzz_targets"><code>fuzz_targets/</code></a></div></div>
<div class="risk"><div class="sev p2">P2</div><div><h3>为时延回归准备固定硬件基线</h3><p>布局与分配已是确定性硬门,但 Criterion 时延仍受本机频率、后台负载和 hash seed 影响。若要阻断时延回归,需要固定 runner、base/head 交错轮次和原始 artifact。</p></div><div class="impact">残余风险:性能漂移<br><a href=".github/workflows/performance.yml"><code>performance.yml</code></a></div></div>
<div class="risk"><div class="sev p3">P3</div><div><h3>继续隔离 3.1 兼容 surface</h3><p>旧 pattern dispatch 和 umbrella <code>Error</code> 为不升级大版本而保留,但内部查询已不再依赖公开 dispatch,并有下游 API 合约与 semver 基线。未来删除必须留到主版本。</p></div><div class="impact">残余风险:演进成本<br><a href="API.md"><code>API.md</code></a></div></div>
<div class="callout success"><strong>安全结论:</strong>旧 packed safe API 已从发布 surface 移除;<code>experimental-packed</code> 仅保留为 3.1 兼容 no-op feature。内部 unchecked helper 已改成真实 <code>unsafe fn</code> 边界,每个调用点必须给出局部证明;<a href="SAFETY.md"><code>SAFETY.md</code></a> 集中记录稳定不变量和 Miri 矩阵。</div>
</div>
</section>
<section id="engineering">
<div class="wrap">
<div class="section-head">
<div class="section-no">06 / EVIDENCE</div>
<div><h2>工程质量:证据链闭合,发布路径 fail-closed</h2><p class="sub">3.1 将测试、文档、MSRV、Miri、供应链、API 兼容和确定性性能证据拆成五个固定 SHA 的 workflow。README、crate metadata 与实际门禁一致,发布验证先于 tag 和 publish。</p></div>
</div>
<div class="table-wrap"><table>
<thead><tr><th>验证</th><th>结果</th><th>事实</th><th>判断</th></tr></thead>
<tbody>
<tr><td><code>cargo test --all-features</code></td><td><span class="status pass">PASS</span></td><td>203/203</td><td>171 unit/integration + 32 doctests</td></tr>
<tr><td><code>cargo clippy --all-targets --all-features -- -D warnings</code></td><td><span class="status pass">PASS</span></td><td>0 warnings</td><td>现代工具链洁净</td></tr>
<tr><td><code>cargo fmt --all -- --check</code></td><td><span class="status pass">PASS</span></td><td>clean</td><td>格式门禁正常</td></tr>
<tr><td>no_std + serde/bytes/simd matrix</td><td><span class="status pass">PASS</span></td><td>stable + Rust 1.95</td><td>功能组合可构建/测试</td></tr>
<tr><td><code>cargo package</code></td><td><span class="status pass">PASS</span></td><td>79 files · 394.3 KiB</td><td>发布包自包含且排除未跟踪 docs</td></tr>
<tr><td>Miri matrix</td><td><span class="status pass">PASS</span></td><td>61 tests</td><td>三种表示与 API/bytes 边界通过</td></tr>
<tr><td>rustdoc <code>-D warnings</code></td><td><span class="status pass">PASS</span></td><td>22/22 documented;2/2 examples</td><td>default/no-default/all-features 均受控</td></tr>
<tr><td>Rust 1.95 packaged consumers</td><td><span class="status pass">PASS</span></td><td>default + feature consumers</td><td>MSRV 对发布包与 SIMD 成立</td></tr>
<tr><td>API compatibility</td><td><span class="status pass">PASS*</span></td><td>post-retirement baseline: 196 pass</td><td>对 3.0.0 有 3 个已批准的实验安全移除</td></tr>
<tr><td>Python repository tests</td><td><span class="status pass">PASS</span></td><td>24 tests</td><td>workflow 与证据 schema 自包含</td></tr>
<tr><td><code>cargo audit</code></td><td><span class="status pass">PASS</span></td><td>0 vulnerabilities / 0 warnings</td><td>无失维护的项目依赖</td></tr>
<tr><td>fuzz targets</td><td><span class="status pass">PASS</span></td><td>2 targets build</td><td>编译有门;持续执行仍为改进项</td></tr>
</tbody>
</table></div>
<h3 style="margin-top:40px">当前证据链的四个支点</h3>
<div class="grid-2">
<article class="card"><h4>五类 workflow 分责</h4><p>CI、Safety、Performance、API Compatibility 与 Release 分离,第三方 Actions 固定到完整 commit SHA,职责与 README 声明一致。</p><p><a href=".github/workflows"><code>.github/workflows/</code></a></p></article>
<article class="card"><h4>发布顺序 fail-closed</h4><p>版本输入经环境变量与格式校验;fmt、Clippy、test、package 和内容校验全部通过后,才创建 tag 并发布。</p><p><a href=".github/workflows/release.yml"><code>release.yml</code></a></p></article>
<article class="card"><h4>确定性性能 schema v3</h4><p>布局、分配次数、分配字节、Arc 指针复用与 10k 容器密度由机器可读证据和 Python verifier 共同验证。</p><p><a href="PERFORMANCE.md"><code>PERFORMANCE.md</code></a></p></article>
<article class="card"><h4>文档与元数据同源</h4><p>3.1.0、Rust 1.95、feature surface、安全边界与性能承诺在 Cargo metadata、README 和根级专题文档中一致。</p><p><a href="README.md"><code>README.md</code></a> · <a href="Cargo.toml"><code>Cargo.toml</code></a></p></article>
</div>
<div class="callout success"><strong>工程结论:</strong>初始审计中的 MSRV、Miri、rustdoc、依赖、文档和发布顺序缺陷均已有自动门禁。当前主要工程缺口不再是“证据是否存在”,而是把 fuzz 动态执行与固定硬件时延基线提升到同等可重复级别。</div>
</div>
</section>
<section id="roadmap">
<div class="wrap">
<div class="section-head">
<div class="section-no">07 / ROADMAP</div>
<div><h2>从 95 分继续收敛:强化连续证据,不扩大 3.1 surface</h2><p class="sub">安全退役、24B 表示、MSRV、发布与 API 门禁已经落地。后续工作应围绕可重复测量和写入侧成本展开;兼容性清理不在 3.1 内破坏式推进。</p></div>
</div>
<div class="roadmap">
<article class="road-step"><div><h3>持续执行 fuzz corpus</h3><ul><li>在 Linux sanitizer runner 上定时执行两个稳定 target,而不只验证可编译。</li><li>保存 crash artifact、seed corpus 与最小化输入,并把重现命令写入 Safety workflow。</li><li>优先覆盖 UTF-8 边界、共享转换、substring range 与 clone/drop 交错。</li></ul></div></article>
<article class="road-step"><div><h3>建立固定硬件时延基线</h3><ul><li>使用固定 CPU runner、锁定频率与 affinity,交错执行 base/head。</li><li>上传 Criterion 原始 artifact、环境指纹与置信区间,不用单次 geomean 阻断发布。</li><li>布局与 allocation schema v3 继续作为跨 runner 的确定性硬门。</li></ul></div></article>
<article class="road-step"><div><h3>优化写入侧长值路径</h3><ul><li>对 upper/lower/replace/repeat 与 substring 分别测量中间 <code>String</code> 和 freeze copy。</li><li>保持 <code>From<Arc<str>></code> 零拷贝;为常见 exact/spare 容量分布建立真实 workload。</li><li>只有在 API 语义清楚且 allocation contract 不退化时才引入专用 builder 快路径。</li></ul></div></article>
<article class="road-step"><div><h3>维持 3.1 兼容边界</h3><ul><li>继续保留 deprecated pattern dispatch 与既有 <code>Error</code> 类型,不在 3.1 删除。</li><li>内部实现保持依赖私有 classifier;通过 cargo-semver-checks 和 downstream contract 监控 surface。</li><li>若未来允许主版本,再单独评估兼容 shim 与错误模型清理。</li></ul></div></article>
</div>
</div>
</section>
<section id="method">
<div class="wrap">
<div class="section-head">
<div class="section-no">08 / METHOD</div>
<div><h2>方法、范围与可复现命令</h2><p class="sub">复审基线为 <code>300b313c3217a46a470c9b590ffc9e80584e9759</code>,最终报告通过独立 PR 合入。报告把机器可重复的测试、布局、分配、MSRV 和 API 合约与本机 Criterion 诊断严格分开;评分不依赖一次性纳秒结果。</p></div>
</div>
<div class="grid-3">
<article class="card"><div class="kicker">环境</div><p class="mono">Windows NT 10.0.26200<br>x86_64-pc-windows-msvc<br>i7-11700K @ 3.60GHz<br>rustc/cargo 1.96.1<br>LLVM 22.1.2</p></article>
<article class="card"><div class="kicker">仓库规模</div><p class="mono">15 src files / 2,326 lines<br>16 integration files / 1,764 lines<br>10 benchmarks / 1,934 lines<br>2 fuzz targets<br>5 workflows<br>3 normal deps at all-features</p></article>
<article class="card"><div class="kicker">统计口径</div><p>Criterion 使用 median;95% CI 重叠时不作速度排名。代码行数不代表覆盖率,测试数量也不代替 property/fuzz coverage。评分扣分只对应仍可复现的残余风险。</p></article>
</div>
<details open><summary>核心验证命令</summary><div>
<span class="cmd">cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo test --no-default-features --features serde,bytes
cargo check --no-default-features
RUSTDOCFLAGS="-D warnings" cargo doc --lib --all-features --no-deps
RUSTDOCFLAGS="-D warnings" cargo doc --lib --no-deps
cargo +1.95 check --lib --all-features
& scripts\check-msrv-package.ps1 -Msrv 1.95 -AllowDirty
cargo test --test allocation_contract --all-features -- --test-threads=1
cargo test --test layout_snapshot --all-features -- --nocapture
cargo package --allow-dirty
python -m unittest discover -s scripts/tests -p "test_*.py" -v</span>
</div></details>
<details><summary>性能命令</summary><div>
<span class="cmd">cargo bench --bench shared_backing -- __allocation_evidence_only__ --noplot 2>&1 | Tee-Object target/allocation-evidence.log
python scripts/verify-allocation-evidence.py target/allocation-evidence.log
cargo bench --bench comprehensive -- size_scaling --warm-up-time 0.5 --measurement-time 1 --sample-size 30 --noplot
cargo bench --bench mq_topic -- mq_topic_insert --warm-up-time 0.5 --measurement-time 1 --sample-size 30 --noplot</span>
<p>allocation evidence 是 schema-v3 硬门;Criterion 运行期间存在桌面后台负载,未固定 governor/affinity,也未做 base/head 双向轮次。CI 重叠的差异按“近似持平”处理。</p>
</div></details>
<details><summary>Miri / 供应链 / 受限验证</summary><div>
<span class="cmd">cargo +nightly miri test --lib --no-default-features
cargo +nightly miri test --test api_contract --no-default-features
cargo +nightly miri test --test basic --no-default-features
cargo +nightly miri test --test bytes --features bytes
cargo audit --json
cargo +nightly fuzz build</span>
<p>Miri 本地矩阵共 61 项通过。两个稳定 fuzz target 纳入编译门禁,但本轮不把“build pass”表述为动态 fuzz pass;cargo audit 基于本地更新后的 advisory database。</p>
</div></details>
<h3 style="margin-top:38px">关键证据索引</h3>
<div class="table-wrap"><table>
<thead><tr><th>主张</th><th>一手证据</th></tr></thead>
<tbody>
<tr><td>三态表示与 23B inline</td><td><a href="src/cheetah_string/repr.rs"><code>repr.rs</code></a>;<a href="src/inline.rs"><code>inline.rs</code></a></td></tr>
<tr><td>24B provenance-safe layout</td><td><a href="LAYOUT.md"><code>LAYOUT.md</code></a>;<a href="tests/layout_snapshot.rs"><code>layout_snapshot.rs</code></a></td></tr>
<tr><td>Arc adoption / 构造 / 冻结</td><td><a href="src/cheetah_string/construct.rs"><code>construct.rs</code></a>;<a href="src/builder.rs"><code>builder.rs</code></a></td></tr>
<tr><td>allocation schema v3</td><td><a href="tests/allocation_contract.rs"><code>allocation_contract.rs</code></a>;<a href="PERFORMANCE.md"><code>PERFORMANCE.md</code></a></td></tr>
<tr><td>memchr/memmem/Finder</td><td><a href="src/search.rs"><code>search.rs</code></a>;<a href="benches/pattern.rs"><code>pattern.rs</code></a></td></tr>
<tr><td>MQ topic workload</td><td><a href="benches/mq_topic.rs"><code>mq_topic.rs</code></a></td></tr>
<tr><td>稳定 unsafe / retired feature</td><td><a href="SAFETY.md"><code>SAFETY.md</code></a>;<a href="tests/feature_contract.rs"><code>feature_contract.rs</code></a></td></tr>
<tr><td>3.1 API 与 error contracts</td><td><a href="API.md"><code>API.md</code></a>;<a href="tests/api_contract.rs"><code>api_contract.rs</code></a></td></tr>
<tr><td>MSRV / feature 声明</td><td><a href="Cargo.toml"><code>Cargo.toml</code></a>;<a href="scripts/check-msrv-package.ps1"><code>check-msrv-package.ps1</code></a></td></tr>
<tr><td>CI、安全、性能、API 与发布</td><td><a href=".github/workflows"><code>.github/workflows/</code></a></td></tr>
</tbody>
</table></div>
</div>
</section>
<footer class="foot">
<div class="wrap foot-line">
<div>Independent repository re-audit · generated 2026-08-12<br><span class="mono">CheetahString v3.1.0 · baseline 300b313</span></div>
<button class="print-btn" type="button" onclick="window.print()">打印 / 导出 PDF</button>
</div>
</footer>
</main>
<script>
const links = [...document.querySelectorAll('nav a')];
const sections = links.map(a => document.querySelector(a.getAttribute('href'))).filter(Boolean);
const observer = new IntersectionObserver(entries => {
entries.filter(e => e.isIntersecting).forEach(entry => {
links.forEach(a => a.classList.toggle('active', a.getAttribute('href') === '#' + entry.target.id));
});
}, { rootMargin: '-18% 0px -70% 0px' });
sections.forEach(section => observer.observe(section));
if (links[0]) links[0].classList.add('active');
</script>
</body>
</html>