本页目录
Checkers · L1 / L2 / L3
三层检查,各抓一类 bug。L1 加 L3 是纯逻辑、强制开;L2 可选,调一个小 LLM。
L1 · Schema(强制)
校验每个原子的结构是否符合所属 kind 的 schema。必填字段齐不齐?装饰器约束满不满足?
atom id 长不长成 @scope/kind-kebab-name 的样子?跨原子引用在 Prime 内部能不能解析?
// packages/compiler/src/checker-l1.ts
export function checkL1(ast: PrimeAST): Diagnostic[] {
const errors: Diagnostic[] = [];
for (const atom of ast.atoms) {
errors.push(...validateRequiredFields(atom));
errors.push(...validateIdShape(atom));
errors.push(...validateKindSchema(atom));
errors.push(...validateEdgeShape(atom));
}
return errors;
} 开销:每个原子约 5 ms。没有 API key 也能跑。
L2 · 语义 LLM 检查(可选)
调一个小 LLM(默认 DeepSeek)抓语义漂移。问的是:body 跟 metadata 自相矛盾吗?
一条 rule 上写着 severity: low,可 remediation 描述的是关键无障碍阻断 ——
这就是 L2 要标的事。
// packages/compiler/src/checker-l2.ts (excerpt)
const prompt = `Atom ${atom.id} of kind ${atom.kind}.
Metadata says: severity=${atom.severity}, applies-to=${atom.appliesTo}.
Body says: "${atom.body}"
Does the body's tone, scope, or severity match the metadata?
Reply: { "ok": bool, "reason"?: string }
`;
const verdict = await aiClient.json(prompt);
if (!verdict.ok) {
diagnostics.push({ atom: atom.id, message: verdict.reason });
}
开销:DeepSeek 上每个原子约 $0.0001;结果按内容 hash 缓存到 .l2-cache.json。
没 API key 的构建会跳过 L2,并在输出里加一条 notice。
L3 · 跨原子(强制)
在解析后的边图上走一遍。三类错:
requires链里的环 —— 加载顺序解不开。- 矛盾 —— 带
contradicts边的原子,又同时出现在某条组合 contract 里。 - kind 不匹配 ——
validates-with从一条 rule 指向另一条 rule(应该指向 source / metric / check)。
// packages/compiler/src/checker-l3-cross.ts (excerpt)
function detectCycles(graph: EdgeGraph): Cycle[] {
// Tarjan's SCC over the requires-only subgraph
const sccs = stronglyConnectedComponents(graph.subgraph('requires'));
return sccs.filter((scc) => scc.size > 1).map(toCycle);
}
function checkContradicts(atoms: Atom[]): Diagnostic[] {
const ds: Diagnostic[] = [];
for (const atom of atoms) {
for (const c of atom.contradicts) {
const target = byId.get(c);
if (!target) continue;
const sharedScope = scopesContaining(atom).filter(
(s) => scopesContaining(target).includes(s),
);
if (sharedScope.length > 0) {
ds.push(scopeContradictsError(atom, target, sharedScope));
}
}
}
return ds;
} 诊断格式
三种 checker 输出统一的 Diagnostic 形状:
interface Diagnostic {
level: 'error' | 'warning' | 'info';
layer: 'L1' | 'L2' | 'L3';
atom: string; // atom id
message: string;
hint?: string; // suggested fix
source?: { file: string; line: number };
} 怎么跑
# All three on a whole sources tree
prime check --registry
# Only L1 + L3 (no API key needed)
prime check --registry --no-l2
# Single file
prime check primes/sources/@my/rule-x.prime