impeccable 生产级加固实战:用 /harden 全面处理错误态、国际化、文本溢出与边界场景
导读
本文围绕设计语言项目 Impeccable 中 /harden 命令的完整规范(reference/harden.md)展开,讲解如何把一个"只对完美数据生效"的前端界面,加固成能应对真实用户极端输入、网络故障、多语言与多脚本环境的生产级界面。读完你将掌握:加固前的风险盘点方法、七个核心加固维度的可落地实现(文本溢出、i18n、错误处理、边界条件、输入校验、可访问性与性能韧性)、配套的手动与自动化测试策略,以及该规范在 Impeccable 技能仓库中的源码级定位与用法。
一、/harden 在 Impeccable 命令体系中的定位
Impeccable 将设计工作组织为一组面向 AI 编码 Agent 的子命令,每个命令对应一份独立规范文档,统一登记在 SKILL.md 的 Commands 表中:
| 命令 | 类别 | 描述 |
|---|---|---|
harden [target] |
Refine | 生产就绪:错误处理、i18n、边界场景(见 reference/harden.md) |
polish [target] |
Refine | 上线前的最终质量收尾 |
audit [target] |
Evaluate | 可访问性、性能、响应式等技术质量检查 |
机器可读的命令元数据位于 command-metadata.json,其中对 harden 的触发语义描述得比 SKILL.md 更完整:
"Make interfaces production-ready: error handling, i18n, text overflow, edge case management, and resilience under real-world data. Use when the user asks to harden, make production-ready, handle edge cases, add error states, or fix overflow and i18n issues."
也就是说,只要用户请求中出现 "make it production-ready""handle edge cases""add error states""fix overflow""fix i18n issues" 等意图,就该加载 harden 规范并执行加固。参数 [target] 表示可以指定目标文件或路由;仓库 README.md 中给出了一行最直观的调用示例:
/impeccable harden checkout # Add error handling + edge cases
在命令分类脚本 skill-categories.js 中,harden、polish、optimize、onboard 同属 harden 类别,且类别顺序 ['create', 'evaluate', 'refine', 'simplify', 'harden', 'system'] 表明它属于偏后期、面向"上线前抗风险"的一组操作;在仓库视觉规范 DESIGN.md 中该类别还有专属的 oklch 颜色令牌 category-harden-border 与 category-harden-text 用于相关检测与界面呈现。
本规范在仓库中有多份同步副本:.hermes、skill/、plugin/skills/impeccable/ 三处的内容一致(skill/reference/harden.md 与 plugin/skills/impeccable/reference/harden.md 中交接命令被写为 {{command_prefix}}impeccable polish 占位符形式,安装时会被替换成实际的命令前缀)。下文即按这份规范逐层展开。
二、第一步:先评估加固需求,再动手改
规范开篇就给出立场:只对完美数据生效的设计不算生产就绪。因此加固不是"想起一处补一处",而是先系统性地盘出弱点与边界用例,分为三条测试主线。
1. 用极端输入测试
- 极长文本:姓名、描述、标题等字段填入超长内容;
- 极短文本:空字符串、单个字符;
- 特殊字符:emoji、RTL(从右到左)文本、带重音符号的字母;
- 大数字:百万、十亿级别的数值;
- 大量条目:1000+ 列表项、50+ 下拉选项;
- 无数据:各类空状态(empty states)。
2. 测试错误场景
| 错误场景 | 需要验证的行为 |
|---|---|
| 网络故障 | 离线、慢速、请求超时时的界面表现 |
| API 错误 | 400/401/403/404/500 各状态码的差异化处理 |
| 校验错误 | 表单校验失败提示 |
| 权限错误 | 无权查看/编辑时的呈现 |
| 限流 | rate limiting 被触发时的提示与重试策略 |
| 并发操作 | 重复提交、竞态条件 |
3. 测试国际化
- 长译文(德语通常比英语长 30%)下的布局变化;
- RTL 语言(阿拉伯语、希伯来语);
- 字符集:中日韩(CJK)、emoji 等多字节字符;
- 日期/时间格式差异;
- 数字格式差异(如
1,000与1.000); - 货币符号差异。
规范用一行大写强调收束:"CRITICAL: Designs that only work with perfect data aren't production-ready. Harden against reality."——这也是后续所有加固动作的总纲。
三、七个加固维度:系统性提升韧性
规范将加固工作划分为七个维度,逐一给出做法与可复制的代码。以下按维度展开并补充实现层面的说明。
3.1 文本溢出与换行(Text Overflow & Wrapping)
长文本处理有三种互相补充的 CSS 手段:
/* 单行省略号 */
.truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 多行截断 */
.line-clamp {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* 允许换行 */
.wrap {
word-wrap: break-word;
overflow-wrap: break-word;
hyphens: auto;
}
Flex/Grid 溢出防护:flex 与 grid 子项默认的最小尺寸会跟随内容,导致溢出容器,需要显式允许收缩:
/* 防止 flex 子项溢出 */
.flex-item {
min-width: 0; /* 允许收缩到内容尺寸以下 */
overflow: hidden;
}
/* 防止 grid 子项溢出 */
.grid-item {
min-width: 0;
min-height: 0;
}
响应式文本尺寸:
- 用
clamp()实现流式排版(fluid typography); - 设置可读的最小字号:移动端正文以 16px 为底线,只有真正次要的文本才允许 14px。这条"16px 地板"并非 harden 独有——字体与排印规范 reference/typeset.md 明确写着 "Keep body copy comfortably readable and zoomable. Use 1rem / 16px as the ordinary web body floor unless a dense role, platform convention, or user setting justifies otherwise."。harden 特别补充了背后的移动端成因:iOS Safari 会对小于 16px 的聚焦输入框强制放大页面,从而破坏表单布局;
- 测试 200% 缩放下文本缩放;
- 确保容器随文本扩展而非被文本撑破。
3.2 国际化(i18n)
为译文扩展预留空间:
- 为翻译文本预留 30%–40% 的空间预算;
- 用能自适应内容的 flexbox/grid;
- 优先用"通常最长的语言"(一般是德语)做测试;
- 避免给文本容器写固定宽度。
React/JSX 中"假设短英文"是典型反例:
// ❌ Bad: Assumes short English text
<button className="w-24">Submit</button>
// ✅ Good: Adapts to content
<button className="px-4 py-2">Submit</button>
RTL(从右到左)支持:核心是用逻辑属性(logical properties)替代物理属性,使布局自动跟随书写方向:
/* 使用逻辑属性 */
margin-inline-start: 1rem; /* 而不是 margin-left */
padding-inline: 1rem; /* 而不是 padding-left/right */
border-inline-end: 1px solid; /* 而不是 border-right */
/* 或借助 dir 属性 */
[dir="rtl"] .arrow { transform: scaleX(-1); }
字符集支持:全链路使用 UTF-8 编码;测试中文/日文/韩文(CJK);测试 emoji(单个可达 2–4 字节);覆盖拉丁、西里尔、阿拉伯等不同书写系统。
日期/时间与数字/货币格式化:交给标准化的 Intl API,而不是手写格式:
// ✅ 用 Intl API 做正确的本地化格式
new Intl.DateTimeFormat('en-US').format(date); // 1/15/2024
new Intl.DateTimeFormat('de-DE').format(date); // 15.1.2024
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(1234.56); // $1,234.56
复数规则(Pluralization):不能用英文式"加不加 s"的假设去处理其他语言的复数,例如俄语、阿拉伯语有多套复数形式。规范的示例:
// ❌ Bad: Assumes English pluralization
`${count} item${count !== 1 ? 's' : ''}`
// ✅ Good: Use proper i18n library
t('items', { count }) // Handles complex plural rules
3.3 错误处理(Error Handling)
网络错误要满足五个要素:给出清晰的错误文案;提供"重试"按钮;说明发生了什么;适用时提供离线模式;覆盖超时场景。可恢复的错误态 UI 是标准做法:
// 带恢复路径的错误态
{error && (
<ErrorMessage>
<p>Failed to load data. {error.message}</p>
<button onClick={retry}>Try again</button>
</ErrorMessage>
)}
表单校验错误:错误提示内联展示在字段附近;文案清晰具体;给出修正建议;不要无谓地阻断提交;出错时保留用户已输入的内容(不要清空表单)。
API 错误:按状态码做差异化处理,规范给出了一张可直接对照的分诊表:
| 状态码 | 处理方式 |
|---|---|
| 400 | 展示具体的校验错误 |
| 401 | 跳转登录 |
| 403 | 展示权限不足错误 |
| 404 | 展示"未找到"状态 |
| 429 | 展示限流提示 |
| 500 | 展示通用错误并引导联系支持 |
优雅降级(Graceful degradation):核心功能在无 JavaScript 时也能工作;图片必须有 alt 文本;采用渐进增强;为不支持的新特性提供降级方案。
3.4 边界条件与极端场景(Edge Cases & Boundary Conditions)
空状态:覆盖"列表无条目""无搜索结果""无通知""无数据可展示",并给出明确的下一步动作。
加载状态:覆盖首次加载、分页加载、刷新三种时机;用"正在做什么"的措辞(如 "Loading your projects...")而非笼统的 spinner;长操作用时间估算。
大数据集:使用分页或虚拟滚动;提供搜索/过滤能力;做性能优化;绝不一次性加载全部 10000 条。
并发操作:防止重复提交(加载期间禁用提交按钮);处理竞态条件;乐观更新要带回滚;设计冲突解决策略。
权限状态:覆盖无权查看、无权编辑、只读模式,并清楚解释原因。
浏览器兼容:为新特性准备 polyfill;为不支持的新 CSS 提供回退;用特性检测(feature detection)而非浏览器嗅探;在目标浏览器中测试。
3.5 输入验证与净化(Input Validation & Sanitization)
客户端校验:必填字段、格式校验(邮箱、电话、URL)、长度限制、正则 pattern、自定义校验规则。
服务端校验(永远要做):绝不能只信客户端校验;所有输入都要在服务端校验与净化;防御注入攻击;做限流。
约束声明:用原生属性把约束写清楚,并用 aria-describedby 关联提示文案,让约束对屏幕阅读器也可感知:
<!-- 设置清晰的约束 -->
<input
type="text"
maxlength="100"
pattern="[A-Za-z0-9]+"
required
aria-describedby="username-hint"
/>
<small id="username-hint">
Letters and numbers only, up to 100 characters
</small>
3.6 可访问性韧性(Accessibility Resilience)
- 键盘导航:全部功能可键盘触达;Tab 顺序符合逻辑;模态框内管理焦点;长内容提供跳转链接(skip links)。
- 屏幕阅读器支持:正确的 ARIA 标签;用 live regions 播报动态内容变化;描述性 alt 文本;优先语义化 HTML。
- 高对比度模式:在 Windows 高对比度模式下测试;不能只依赖颜色传达信息;提供替代视觉线索。
3.7 性能韧性(Performance Resilience)
慢网速:渐进式图片加载;骨架屏(skeleton screens);乐观 UI 更新;用 Service Worker 提供离线支持。
内存泄漏:组件卸载时清理事件监听、取消订阅、清除定时器/间隔器、abort 未完成的请求。
节流与防抖:
// 搜索输入防抖
const debouncedSearch = debounce(handleSearch, 300);
// 滚动处理器节流
const throttledScroll = throttle(handleScroll, 100);
四、测试策略:把加固变成可验证的闭环
手动测试清单
- 用极端数据测试(极长、极短、空值);
- 在不同语言下测试;
- 离线测试;
- 限速测试(节流到 3G 网速);
- 用屏幕阅读器测试;
- 纯键盘操作测试;
- 在旧浏览器上测试。
自动化测试分层
| 层级 | 覆盖对象 |
|---|---|
| 单元测试 | 边界用例 |
| 集成测试 | 错误场景 |
| E2E 测试 | 关键路径 |
| 视觉回归测试 | 布局/视觉变化 |
| 可访问性测试 | axe、WAVE 等工具 |
值得留意的是,在 Impeccable 的命令体系中这些能力并非全部由 harden 独扛:技术质量角度的系统性检查由 audit 命令(reference/audit.md)覆盖。实际工作中两者是先后关系——audit 负责查出问题,harden 负责针对错误处理、i18n、溢出与边界场景做修复。
五、加固的底线与收尾
规范用一组禁止项锁住加固质量,避免半途而废式的"看起来没问题":
NEVER(永不):
- 假设输入完美——所有输入都要校验;
- 忽略国际化——为全球用户设计;
- 使用笼统的通用错误文案(如 "Error occurred");
- 忘记离线场景;
- 只信客户端校验;
- 给文本用固定宽度;
- 假设文本都是英文长度;
- 单个组件出错就阻断整个界面。
规范同时强调:"Hardening is about expecting the unexpected. Real users will do things you never imagined."
六、加固验收清单:收尾前逐项打勾
在提交之前,用下列极端场景做一轮针对性验收(规范的 Verify Hardening 一节):
- 长文本:尝试 100+ 字符的姓名;
- Emoji:在所有文本字段中使用 emoji;
- RTL:用阿拉伯语或希伯来语测试;
- CJK:用中文/日文/韩文测试;
- 网络问题:断开网络、节流连接;
- 大数据集:用 1000+ 条数据测试;
- 并发操作:快速连续点击提交 10 次;
- 错误:强制触发 API 错误,测试所有错误态;
- 空数据:删光数据,测试空状态。
当上述边界用例全部覆盖后,规范给出的下一步是固定的:交接给 /impeccable polish 做最终收尾(在 skill/ 与 plugin/ 版本中写作 {{command_prefix}}impeccable polish)。这体现的是一种分工理念:harden 负责"扛住真实世界的恶劣输入",polish 负责"上线前的最后视觉与细节打磨",二者一前一后构成完整的上线前流水线,而不是把加固留到最后一刻。
七、从文档到代码:规范在仓库中的落地脉络
如果希望深入本仓库核实本文依据,可以按以下路径对照阅读:
- 规范本体:.hermes/skills/impeccable/reference/harden.md(另有 skill/reference/harden.md 与 plugin/skills/impeccable/reference/harden.md 两份同步副本);
- 命令登记与触发语义:command-metadata.json 与 SKILL.md 的 Commands 表;
- 调用示例:README.md 中的
/impeccable harden checkout; - 命令类别归属:skill-categories.js(
harden、polish、optimize、onboard同属harden类别); - 16px 排版地板与 harden 规范的呼应:reference/typeset.md;
- 类别视觉令牌:
category-harden-border与category-harden-text(见 DESIGN.md)。
把它们串起来就能看到,harden 规范不是一份孤立的清单,而是 Impeccable 生产级设计工作流中"抗风险"这一环的标准动作:当 AI Agent 收到加固类请求时,按命令元数据路由到本规范,逐维修复错误处理、i18n、文本溢出与边界场景,最后用验收清单自检并交接给 polish。对任何团队而言,这套"先盘点风险 → 分维度加固 → 极端数据验收 → 交接打磨"的方法,都可以直接搬进自己的前端交付流程。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00