编译诊断与 API 学习闭环
编译失败先转换为结构化诊断,再确定缺失符号的依赖与版本。首次明确的外部 API 缺口先查缓存,再复用现有 Learning 请求;普通实现错误直接交给 Fixer。生成候选必须通过确定性检查,重新构建成功才算修复完成。
诊断与进展
buildDiagnostics.ts 有界读取最多 64 行诊断块,跳过源码展示与光标行,保留 symbol、location、required、found、reason。支持原 Maven 格式、原始 javac 和 GitHub Actions 时间戳。
原始位置与语义身份分别保留。同一文件的不同缺失符号具有不同身份,同符号多处报错保留所有位置;仅移动行号不会被视为新 API 缺口。进展、回滚与知识反馈从诊断内容重建身份,兼容保留了语义字段的旧记录。信息不足时标记未解析,不猜测包名。
首次失败学习
学习资格有三种结果:
| 结果 | 条件与处理 |
|---|---|
LEARN | 公开符号、目标版本与编译依赖归属明确,先读取公共知识缓存 |
REPAIR_DIRECTLY | 项目内部类、方法、构造器或普通实现错误,直接修复 |
INSUFFICIENT_CONTEXT | 符号、依赖或版本不足,保留原因并降级,不能当成确认的 API 缺口 |
依赖上下文来自生成项目的有效编译依赖声明。POM 声明提供查证目标,不能证明 SNAPSHOT 的实际 JAR 内容。完整 POM 指纹绑定请求与结果,取得修复租约后再次校验,防止依赖变化后采用旧事实。插件依赖、dependencyManagement、非激活 profiles、测试或运行时依赖不会据此获得自动学习资格。
自动查证复用 learning/start|step|status、现有工具授权、额度、取消、租约与恢复机制。同一诊断和依赖环境的请求或终态结果可恢复;缓存命中、功能关闭、存储不可用、证据不足、待审核、超时和服务失败分别记录。Learning 不消耗 repairAttempts;只有实际应用文件改动、准备重新构建时计入一次修复。
负面 API 事实
负面事实只说明完整限定符号在明确作用域内不可用,不推荐或编造替代 API。
| 证据 | 自动采用范围 |
|---|---|
| 当前 javac 缺失类或成员诊断 | 当前任务、原始编译轮次、完整依赖与 POM 指纹;仅保存于任务私有状态 |
| 已确定性验证的制品完整符号清单 | 精确依赖身份与制品指纹限定的共享事实 |
| 经过验证或人工审查的官方版本化完整清单 | 精确版本限定的共享事实 |
模型推断、搜索无结果或普通 contradicted | 不激活共享负面事实 |
方法重载失败不能证明整个方法不存在,因此不会自动形成禁止整个方法的编译负面事实。包缺失也不会形成禁止整个命名空间的事实。
compileApiEvidence.ts 从经过校验的完整清单确定类型及枚举常量缺失。类型必须明确归属公开依赖,且整个 classpath 中没有同名类型;枚举常量还要求 owner 唯一、继承链完整且没有同名继承字段。方法、普通字段、重名类或不完整继承关系不会自动入库。没有完整清单证据时使用任务内编译事实,不扩大结论。
learning/step 复用 negativeApiFacts.ts 的确定性校验,在同一次 D1 batch 中提交公共来源、负向事实和按 need 记录的结果引用。每个写入受任务状态 fence、job lease、revision 和授权保护。结果只有在引用仍有效且已经提交时才能为 ready,刷新和模型恢复也重新校验。按符号、版本、依赖坐标和实际 JAR SHA-256 去重,有效期最多 90 天;已停用记录只能通过新的完整制品验证及原证据哈希的比较恢复。
SNAPSHOT 的同名版本也以实际 JAR SHA-256 匹配缓存。制品更新后旧事实不能命中。编译事实在新编译轮次、POM、依赖集合、任务或版本变化后失效;新诊断可重新建立事实。
候选检查同时约束 Fixer 上下文和 Java 文件。匹配完整限定名、明确 import、可确定归属的通配 import 与成员引用,忽略注释和字符串,不禁止不同包中的同名类。字段和枚举成员统一为 Owner#member,兼容诊断与查询中的点号写法。候选违反事实时复用原有一次重新生成限制;仍不合格则不应用。提交重建前再次检查完整项目候选,若其他文件仍引用已确认不可用符号,恢复本轮全部修改,不消耗修复次数。
同一依赖环境内的正负结论冲突时暂停两者自动采用,输出重新验证提示。版本或指纹不同的结论不直接冲突;置信度不能覆盖当前编译证据。
存储兼容与部署
新增迁移 0005_negative_api_facts.sql,历史迁移与旧知识读取保持兼容。共享表按符号与精确依赖身份索引,记录来源、证据哈希、版本、状态和过期时间。编译事实不进入公共表,不持久化项目源码。
部署前应用新增 D1 迁移;已有 negative_api_facts 表和索引且 Learning 的 DB 绑定有效时,无需新增后台配置。表未就绪或读取超时时记录存储降级,并继续使用任务内编译约束。
构建仓与附带的 public/maven.yml、public/compile_api_evidence.py 同步增加独立证据步骤,保持原编译命令、权限和产物保留策略。Python 标准库在 javac 前扫描实际 classpath,输出 compile_api_evidence.v1,包含构建提交、run/attempt、完整 POM 哈希、实际依赖坐标、JAR SHA-256、公开符号和完整性标记。先冻结证据脚本,采集失败继续原有编译并禁止共享入库,不新增生产依赖。
服务端通过 GitHub 步骤日志接口只读取专属步骤;核对 run/attempt、提交、POM 和经过审查的 workflow/scanner Git blob。生成文件不得覆盖 .github、.git 或证据脚本。只有可信公共仓库下载的制品与实际 JAR 逐字节哈希一致时才是公共证据。证据日志有大小、数量和时限上界,损坏、截断、来源不可信或超限均降级。
公开快照可包含 negativeFactsUsed,界面分别显示“已验证不可用”和“命中不可用 API 缓存”。公共表仅保留公开符号、制品身份及缺失结论,项目源码、任务内容和私有身份不进入公共记录。
回归与可观测性
实际 #452 日志来自 该历史构建,固定于 tests/fixtures/build-failures/javac-missing-class.log。其他日志样本为合成回归结构,来源说明见同目录 README。
回归覆盖原始日志、符号与资格判定、缓存查找、模拟 Learning 终态、修复上下文、候选拒绝、依赖失效与进展比较;端点测试模拟 fix → start → step → status → fix 的状态转换。
结构化事件包括 diagnostic_parsed、api_symbol_identified、learning_eligible、learning_skipped、learning_cache_hit、learning_verified、negative_api_applied 和 fix_candidate_rejected。事件留在任务调试流;公共事实写入不包含源码、密钥或私有任务内容。
回归还使用真实 SQLite 事务验证 A 首次写入、B 相同制品命中、C SNAPSHOT 更新后重新验证,以及取消、过期租约、revision/POM 改动、证据冲突、停用后重新验证、事务失败与重复刷新。每个交付版本执行 npm test、npm run build、tsc --noEmit 和构建证据测试;另完成真实受控编译与界面基础视觉检查。先审查并合并构建仓证据 PR,再合并应用仓闭环 PR。