分析轨让读者发问,在同一份索引上、由同一个核判决。
工作原理页上每个家族各判树上已有的一种熵;发问守同一套承诺:对实测事实做算术,无模型、无浮点,每个常数钉在实现它的源码行上。家族接第十五族续编号,每族一册;每个小标题都链到 docs/reference/methodology.md 里的完整推导。
判决家族拿实测事实比一条写下的阈值;分析家族拿一个程序——问题或规则文件——在索引的事实上作答,阈值由读者自己写。Rust 度量与回标,Haskell 核判决。协议 9.0.0 起,核要读的文本(程序原文、被度量的路径)经本机管道过线;事实表里的名字仍以哈希过线。
用 CE Datalog 对索引的事实——文件、目录、引用、单元、复杂度、已判的克隆对与文档重复对、提及、路径类——提问,答案带推导链;规则文件的断言是门:违规是一行见证加推导,ce rules 见第一条即退 1。五项常见检查不必写 Datalog:ce.toml 的 [rules.pack] 可开目录成环、扇入 / 扇出上限、分层与禁止引用对,核把它们渲染成同一种语言(谓词头保留 pack_ 前缀),与规则文件一起判。
clause := atom ':-' body '.' | '?-' body '.' | 'assert' atom ':-' body '.'
lit := atom | 'not' atom | expr op expr | Var '=' expr | Var '=' agg(Vars : body)
prelude: entry(N) :- role(N, _). reach(M) :- reach(N), ref(N, M, K, _), K != asset, K != refdef.
dead(F) :- file(F), not reach(F). depends · same_dir · dir_ref
strata : 头位于体内每个被否定或被聚合的谓词之上;SCC 内的负边是程序错误
eval : 逐层半朴素求值,建在惰性位掩码索引上;元组的第一条推导即其出处
度量侧送出程序的三段原文(前奏、规则文件、问题)与程序点名的事实表;表里的名字以 fnv1a64 哈希与请求内 id 上线,回来再回标。核把原文切成 [kind, value] 记号,再解析(手写递归下降),查元数、类别(变量、谓词位置与常量类别上的并查集)、安全性(域界:变量须先被正原子或绑定绑定才可读)与分层,逐层求值,答回目标元组、违规、推导行与错误——错误落在记号上,映回 line:column。推导树整棵或不出:超结点预算的计数、不截断。记号与事实行先定价(超限给完整的降级应答);派生元组超限整次作废;没有这个家族的核是具名未判决。内置 dead(F) 即 ce deadcode 的文件级判决;ce.rules 九条断言是 CI 第七条狗粮腿。
函数内的死代码:无路径到达的语句、无路径读到的存储、没人读的局部量,没人读的形参只作顾问。ce flow 列出,守卫数一次写入新增的,Stop 行只记、不拦停。
tables : stmts [u, seq, parent, kind, flags, aux] · vars [u, v, declSeq, flags] · uses [u, seq, v, mode]
cfg : 结构化种类展开;try 体的每条语句都可能到达每个 catch;
有 finally 时,体与 catch 里的语句还可能经它向外抛出;每个 try 一个 finally 汇合点
kind 0 : unreachable = 入口无路径可达,每段极大连续 seq 一条发现
kind 1 : dead_store = 下次写或出口之前没有路径读到的写(反向活性)
kind 2 : unused_local = 无读 · kind 3 : unused_param = 无读(顾问,从不判决)
skip : 含动态语句的单元不做部分判决,只计数
每语言一张 FlowSpec 表,把十个语言(Python、TypeScript 与 TSX、Rust、Go、C、C++、Java、Lua、R)的每个单元降成四张整数表。核建控制流图,从入口走可达性、反向求活性到不动点,答回 [unit, kind, seq, var, seqEnd] 行。近似只加路径(finally 是一个汇合点、后继取待续目标的并集;表达式位置的出口不降表),所以只会漏报、不会捏造。语言的盲评精度考题在门读的每一类零误报才算判决:十个都获准判决(门读的每一类都过或空过——样本里没有阳性也没有误报),C++、R、Rust、TypeScript 用第二代考题;未用形参处处只是顾问。守卫类 [flow] tier 出厂 observe,按(单元,种类,变量)的多重集差数新增,挪位置的不算。
每个克隆组怎样合成一个函数:成员不同处成为参数,答案是参数个数、该留的成员、省下的行数与可行性(不可行给原因)。只当顾问:没有门读它,ce merge 出文档即退 0。
groups : T1/T2 dedup 族(某单元占每个成员 ≥ 9/10 时取整单元,否则把片段裁到成员共有的形状)· T3 已判对 trees : clone/1 的后序 (lab, lld),不带附加结点(注释),+ leaf = 叶结点字节的 fnv1a64(内部结点为 0)+ slot 0 stmt · 1 expr · 2 type · 3 name · 4 other align : T1/T2 同构,洞 = 不同的叶;T3 取自顶向下收窄的树编辑映射,重标与不等长间隙是洞 params : 每个不同的取值向量一个;可行当且仅当每个洞都是表达式或名字、params ≤ 6 且 savings > 0 reason : 3 跨语句的间隙,1 位置(语句或其他),2 类型位置,4 参数多于六个,5 没省下行 kept : 所在文件入度最大的成员;savings = Σ lines − (skeleton lines + members × 1),片段的行数取其保留段
每个成员按 clone/1 编码建树,多带叶结点原文哈希与位置类两列(每语言一张表,读流表的语句类);答案回标成每个参数上每个成员的原文,间隙洞给整段森林。树不带注释;片段族只送每个成员都有的那段顶层结点,边界行截断的半条语句不会分出两种形状,合并按保留段的行数定价。核对齐成员、找洞、给参数编号、给合并定价。核会拒收的组——没有函数可合并的 Markdown 与 HTML、没建成的树、形状不一——按原因计数、不送。T3 骨架的行数是诚实的整数估计。本仓与四个外部语料各在一个钉住提交上的建议集被冻结,抽一百条盲判可行性。
目录之间怎么依赖:哪些在底层,拆环最省切哪几条边,哪些文件该挪到常打交道的文件旁,每个目录的扇入、扇出与不稳定度,改一个文件波及哪些文件。只当顾问:没有门读它,ce arch 出文档即退 0。
arcs : 每条文件引用一条 dir(F) → dir(G),每条包引用一条 dir(F) → D;同一目录内的不计
cuts : 逐个 SCC,≤ 14 个目录时走子集规划(exact 1),否则 Eades–Lin–Smyth + 冗余清理(exact 0)
layers : d 无出边时 level(d) = 0,否则 1 + d 所指者的最大 level,切掉的弧不算
cluster: 确定性 Louvain,增益取整数,两层;misplaced = 它的簇在别处的文件严格更多
impact : 沿引用反向广度优先,焦点在深度 0
metrics: fanIn, fanOut, instability = ⌊1000 · out ÷ (in + out)⌋,没有边碰到该目录时为 −1
度量侧送被度量文件的路径与行数、按路径的引用与 --impact 路径;目录树与五张表(文件及其目录与行数、目录、文件到文件与文件到包的引用、焦点)由核自己建,每条切边回标时带背后的文件引用。核把引用折成目录图,逐个强连通分量求反馈弧集,给剩下的分层,在文件图上聚类,走影响面,度量每个目录。贪心切边集极小、未证最小,行上照实标出。本仓在一个钉住提交上的读数被冻结,漂移即度量或核动了。