看见反常 · 动一处 · 抓证据
一个可信工具,要让输入、判断和回滚都看得见
只读 · 与实验共用计算模型
这页解决什么
沿输入选择、规则、依赖闭包、版本报告和回滚 token 阅读。
先确定这次到底检查谁
增量筛选和依赖闭包共同决定边界。
// SECTION:input
export function selectInput(allAssets, changedOnly, includeDependencies) {
const roots = changedOnly ? allAssets.filter((asset) => asset.changed) : allAssets;
return includeDependencies ? dependencyClosure(roots, allAssets) : roots;
}
每条判断都要让机器读得懂
结果包含状态,也标明能否自动修复。
// SECTION:rules
export function evaluateRules(asset, rules) {
return rules.map((rule) => ({
id: rule.id,
status: rule.check(asset) ? 'pass' : 'fail',
fixable: Boolean(rule.fix),
}));
}
一个资源坏了,可能牵动一串文件
缺失依赖必须成为报告里的明确证据。
// SECTION:dependency-closure
function dependencyClosure(roots, allAssets) {
const byId = new Map(allAssets.map((asset) => [asset.id, asset]));
const result = new Map(roots.map((asset) => [asset.id, asset]));
for (const asset of result.values()) {
for (const dependencyId of asset.dependencies) {
const dependency = byId.get(dependencyId);
if (dependency) result.set(dependency.id, dependency);
}
}
return [...result.values()];
}
报告本身就是交付物
输入版本、工具版本和回滚 token 一起保存。
// SECTION:report
export function buildReport(records, inputVersion, toolVersion) {
return {
inputVersion,
toolVersion,
passed: records.filter((record) => record.status === 'pass').length,
failed: records.filter((record) => record.status === 'fail').length,
fixable: records.filter((record) => record.fixable).length,
rollbackToken: hash(records),
};
}
失败时按 token 撤回
不能靠猜文件名恢复上一版。
// SECTION:rollback
export function rollback(report, store) {
if (!report.rollbackToken) throw new Error('missing rollback token');
return store.restore(report.rollbackToken);
}