vicTop-cw/fist-mbt/src/evolve does not have a README file

    Archive

    pub struct Archive {
    items : Map[String, Artifact]
    path : String
    }

    档案库(进程内 Map 存储,持久化由调用方决定)。

    Archive::add

    fn Archive::add(self : Archive, a : Artifact) -> Unit

    添加产物。若 parent 已在库中,累加其 children 计数。 重复添加同一 id(覆盖已有记录)时不再重复累加父节点 children,避免计数虚高。

    Archive::all

    fn Archive::all(self : Archive) -> Array[Artifact]

    全部产物(值数组)。

    Archive::best

    fn Archive::best(self : Archive) -> Artifact?

    最高分产物(空库 None)。

    Archive::dead_ends

    fn Archive::dead_ends(self : Archive, limit? : Int) -> Array[String]

    低分产物(“此路不通”地图):喂回给课程生成器绕开。

    Archive::get

    fn Archive::get(self : Archive, id : String) -> Artifact?

    按 id 取产物。

    Archive::is_duplicate

    fn Archive::is_duplicate(self : Archive, goal : String, threshold? : Double) -> Bool

    查重:某个 goal 是否与库中已有产物高度相似(Jaccard >= threshold)。

    Archive::is_empty

    fn Archive::is_empty(self : Archive) -> Bool

    是否为空档案库。

    Archive::len

    fn Archive::len(self : Archive) -> Int

    产物总数。

    Archive::lineage

    fn Archive::lineage(self : Archive, from : String, depth? : Int) -> Array[(String, Double, String)]

    从某产物沿 parent 链回溯谱系(最多 depth 层),返回 (id, score, goal) 数组。

    Archive::new

    fn Archive::new(path : String) -> Archive

    新建档案库。

    Archive::novelty

    fn Archive::novelty(self : Archive, note : String) -> Double

    新颖性:1 - 与库中 note 的最大 Jaccard 重合。值越高越没见过。

    Archive::sample_parent

    fn Archive::sample_parent(self : Archive, lam? : Double, a0? : Double, rand~ : () -> Double) -> Artifact?

    加权滚轮采样:p_i ∝ s_i · h_i,返回选中产物(空库 None)。 rand 注入 () -> Double([0,1) 均匀),保证可测试。

    Archive::summaries

    fn Archive::summaries(self : Archive, limit? : Int) -> Array[String]

    摘要(高分优先):给课程生成器看的 top-N。

    Artifact

    pub struct Artifact {
    id : String
    parent_id : String?
    goal : String
    note : String
    code : String
    score : Double
    parts : Map[String, Double]
    children : Int
    created_at : String
    }

    档案库中的一个产物。

    Artifact::create

    fn Artifact::create(id~ : String, parent_id~ : String?, goal~ : String, note~ : String, code~ : String, score~ : Double, parts~ : Map[String, Double], created_at~ : String) -> Artifact

    构造一个产物(供外部包创建后加入档案库)。

    Artifact::from_json

    fn Artifact::from_json(j : Json) -> Artifact

    从 JSON 反序列化 Artifact。

    Artifact::to_json

    fn Artifact::to_json(self : Artifact) -> Json

    产出 JSON(供 MCP / 展示)。

    Artifact::with_children

    fn Artifact::with_children(a : Artifact, n : Int) -> Artifact

    返回 children 字段更新后的副本(MoonBit struct 不可变,用于累加子代数)。

    SearchCandidate

    pub struct SearchCandidate {
    name : String
    title : String
    source : String
    mechanism : String
    portable : Bool
    }

    搜索候选:一次外部调研产出的「可移植资产」候选。

    • name:候选名(去重键分量一,如库名/论文名)
    • title:展示标题
    • source:来源(去重键分量二,如 "crate" / "gh" / "paper" / "blogs")
    • mechanism:实现机制/原理描述(供可移植性启发式评估)
    • portable:是否可移植(assess_portability 输出)

    analyze_candidate

    fn analyze_candidate(name : String, title : String, source : String, mechanism : String) -> SearchCandidate

    基础清洗:对五个字段做 trim;portable 依据 mechanism 的启发式(assess_portability)。 去重键 = (trimmed name, trimmed source)。

    assess_portability

    fn assess_portability(c : SearchCandidate) -> Bool

    可移植性启发式评估(粗糙但可复现,规则写死在此注释):

    • mechanism 非空;
    • 长度合理:长度 ≥ 4(过短视为信息不足,不可移植);
    • 含可移植性动作词(大小写不敏感):port / portable / porting / adapt / wrapper / wrap / reuse / extract / portability / 移植 / 封装 / 复用 / embed / integrate / conforms / compat / decouple;

    满足全部三条 → true;否则 false。该评估是计算而非 LLM 自评,供 distill 过滤硬门槛。

    coverage

    fn coverage(a : Array[String], b : Array[String]) -> Double

    覆盖率 |a∩b| / |a|——非对称,a 是基准(根目标),b 是待测文本。 Jaccard 用并集做分母,长文本天然被稀释:子任务多写 200 字模板就"更像漂移", 那是长度惩罚不是目标偏离。coverage 只问"根目标里的词还在不在",多写不罚。

    critic_dup_sim

    fn critic_dup_sim() -> Double

    相似度 ≥ 该值判为"疑似重复/课程漂移",直接建议 reject。 经验阈值:Jaccard 词集重合 0.70 足可视为同一路线。

    critic_most_similar

    fn critic_most_similar(arc : Archive, note : String) -> (String, String, Double)?

    在档案库中找与候选 note 最相似的既有资产,返回 (id, note, 相似度)。 找不到(空库/候选空)返回 None。

    critic_review

    fn critic_review(arc : Archive, note : String, score : Double, threshold? : Double) -> Json

    Critic 综合评审(SAGE Critic 角色,纯计算):
    • novelty = Archive::novelty(note) (相对档案库新鲜度 [0,1])
    • sim = 与最相似既有资产的重合度(最相似者)
    • combined = score==0.5(未计分)→ novelty;否则 0.5score + 0.5novelty (BUG-60:中性 0.5 不参与加权,否则 combined 上限 0.75 永远够不到默认阈值 0.85)
    • admit = sim < dup_sim 且 score_accept(combined, threshold) 返回决策 JSON:{ admit, novelty, score, combined, threshold, sim, rank, reason, top_hit? }。

    distill_candidates

    fn distill_candidates(cands : Array[SearchCandidate]) -> Array[SearchCandidate]

    蒸馏:去重(同 name+source 只留首个)+ 只保留 portable 的 + 按 source 有序输出。 「输出有序」依 source 字符串升序(字典序)排列,稳定(同 source 保持原始先后)。

    evolve_lesson_persist

    fn evolve_lesson_persist(store :
    SqliteStore
    ?, id~ : String, cat : String, reason : String, fix : String, now : String, score? : Double) -> Bool

    把一条教训持久化为 [lesson] 资产(域无关,仅落库 evolve_artifacts)。
    • store 为数据库句柄(None = 内存态,返回 false)
    • id 由调用方生成并保证趋唯一(重复 id 走 upsert 覆盖,避免多轮打回互相覆盖)
    • note 存失败原因、code 存纠偏提示(为空则取 reason) 返回是否成功落库。

    is_duplicate_candidate

    fn is_duplicate_candidate(a : SearchCandidate, b : SearchCandidate) -> Bool

    判重:候选去重键一致(name 与 source 均相等)即视为重复。

    is_robust

    fn is_robust(score : Double, floor? : Double) -> Bool

    稳健性谓词:score 不低于 floor(默认 0.70)视为稳健产物。 用于在采样/蒸馏前过滤掉脆弱产物。

    jaccard

    fn jaccard(a : Array[String], b : Array[String]) -> Double

    两个 token 数组的 Jaccard 相似度 |a∩b| / |a∪b|。

    lesson_goal

    fn lesson_goal(cat : String) -> String

    构造 lesson 类目目标串:goal 前加 [lesson] 前缀(幂等,已有前缀则原样返回)。

    lesson_ts_part

    fn lesson_ts_part(now : String) -> String

    从时间戳提取 id 片段(去分隔符、取前 16 位),用于生成可读且趋唯一的 lesson id。
    fn run_external_search(cmd : String, args : Array[String], runner? : (String, Array[String]) -> Result[String, String]?) -> Result[String, String]

    经注入命令执行外部搜索,返回原始文本(成功 Ok / 失败 Err)。

    不内置网络、不硬编码路径;搜索执行器由调用方通过 注入参数 runner 传入 (供上层接入,测试用 mock 注入)。未注入(默认 None)→ Err「未注入搜索执行器」。

    score_accept

    fn score_accept(score : Double, threshold? : Double) -> Bool

    门禁放行:score 达到阈值(默认 0.85)即通过。 供 evolve_submit 落库前 / Omega gate 复用——决策来自可计算分数,而非 LLM 主观判断。

    score_artifact

    fn score_artifact(coverage : Double, fingerprint_ok : Bool, schema_ok : Bool, accuracy : Double) -> Double

    综合评分公式(返回 [0,1]):

    structural = (fingerprint_ok ? 0.25 : 0) + (schema_ok ? 0.25 : 0) // 结构完整分量,max 0.5 completeness = coverage.clamp(0,1) * 0.25 // 覆盖度分量,max 0.25 correctness = accuracy.clamp(0,1) * 0.25 // 正确度分量,max 0.25

    score = clamp(structural + completeness + correctness, 0, 1)

    理由:
    • 结构完整性(fingerprint + schema)是硬前提,合占 0.5。产物若连"可被验证"都满足不了, 即便内容正确也不该排到前列;故两个结构位每个按 0.25 硬惩罚。
    • 覆盖度与正确度各占 0.25,奖励"解得全、解得对",线性映射可复现。
    • 满分 1.0 当且仅当四项全优(coverage=1、fingerprint、schema、accuracy=1)。

    score_of_lesson

    fn score_of_lesson(score : Double) -> Double

    lesson 分数默认 0.5(教训典型中性样本,不参与 best,但参与死路地图权重)。

    score_rank

    fn score_rank(score : Double) -> String

    档位分档(L4 最高),阈值自定、docstring 写明: L4 score ≥ 0.85 —— 优(放行进入 DGM 高分候选) L3 0.70 ≤ score < 0.85 —— 良 L2 0.55 ≤ score < 0.70 —— 中 L1 score < 0.55 —— 弱(档案库仍保留,作谱系垫脚石)

    tokens

    fn tokens(s : String) -> Array[String]

    切词单真源(BUG-25 标定后重写):ASCII 词 + CJK 单字 + CJK 相邻二字组,去重。

    旧口径是"可见字符集"——对中文等价于逐字拆散,熔断器三态 与 三态熔断器 同分, 而真正的病灶是改写型子任务:子任务合法地换一套词("依赖图恒空"→"增量编译链修复"), 字符集重合因此趋 0,绝对阈值下 15/15 全判漂移(实测见 scripts/calibrate_goal_drift.py)。 新口径加 ASCII 词与 CJK 二字组,让"同词/同词组"才计分: 全量父子对(1222 条)假阳性 16.9%→1.9%,随机错配对照仍 81.3% 判可疑。 口径必须与 scripts/calibrate_goal_drift.py 逐字对齐——数字不是抄来的,是那条命令跑出来的。

    unigrams

    fn unigrams(s : String) -> Array[String]

    可见字符去重集(旧 tokens 口径,保留给兄弟冗余用)。 兄弟重复的典型形状是"词序换位"(数据采集模块 ↔ 采集数据模块), 二字组口径会把它们放行(jaccard 0.556),字符集恰好对词序不敏感(1.0); 实测这个分量在真实非模板家族上不额外增加误报(两种口径同为 34.8%,见标定脚本)。