42 Commits

Author SHA1 Message Date
iomgaa 7a00bc1a28 style(harness): ruff format batching.py + log.py 2026-07-07 20:34:48 -04:00
iomgaa be0e89401e feat(harness): __init__.py public API + lint fixes 2026-07-07 13:45:48 -04:00
iomgaa 2296134f73 feat(harness): runner.py — train loop orchestrator (#13 algorithm fidelity)
Three-level nesting (epoch -> step -> per-skill), slow update 10-step
sequence, checkpoint/resume, early stop, probation accept/reject/rollback.

Key TRM4->TRM5 changes:
- sync -> async (all inference/diagnosis/evolve/validate awaited)
- LLMClient.from_env -> injected LLMProvider (DI via constructor)
- Direct DB/file access -> module functions (workspace/store/log)
- _TrainState as train() local, explicit param passing to helpers

Module-level pure functions extracted for testability:
resume_plan, _guard_infra_failures, _apply_batch_correctness,
_compute_total_steps, _should_early_stop, _format_applied_edits,
_fallback_summary, _write_skip_report, _outcome_to_quadrant_pairs,
_build_comparison_pairs, _batch_from_ids, _snapshot_current_skills.

Tests: 34 unit tests covering 13a-13e sub-tasks.
Radon: all functions Grade B or better.
2026-07-07 13:43:20 -04:00
iomgaa 7bc6fc752c feat(harness): validate.py — async 块序贯验证编排 + Probation 统一定义 2026-07-07 13:20:43 -04:00
iomgaa a6b816db94 feat(harness): checkpoint.py — TrainState 序列化 + 原子写 + 指纹校验 2026-07-07 13:13:37 -04:00
iomgaa d7f1bdeea6 feat(harness): inference.py — async run_inference + DI 2026-07-07 13:04:26 -04:00
iomgaa 886a444d1d feat(harness): momentum.py — async 慢更新动量生成 2026-07-07 13:01:04 -04:00
iomgaa a550d39e1c feat(harness): observation.py — 五张观测表 + step/epoch 报告 2026-07-07 12:55:12 -04:00
iomgaa bd4e438c6c feat(harness): gate_ladder.py — 信息阶梯 + BaselineCache (#6 算法保真) 2026-07-07 12:55:12 -04:00
iomgaa e0f3ee10ec feat(harness): pools.py — 三池切分(test→validation→diagnosis) 2026-07-07 12:48:54 -04:00
iomgaa 9800fef37a feat(harness): batching.py — FFD + round-robin mini-batch (#10 算法保真) 2026-07-07 12:47:33 -04:00
iomgaa d349fe1148 feat(harness): workspace.py — Workspace lifecycle + VersionedSkillStore/PromptStore
- ResolvedPaths frozen dataclass: store_dir, videos_dir, questions_dir,
  skills_dir, prompts_dir, workspace_dir, db_path, analyses_dir, runs_dir
- init_workspace: create ws + copy seed weights from store
- init_workspace_from_seed: create from seed with fail-fast questions check
- load_manifest / resolve_paths: manifest I/O + path resolution
  (skills/prompts resolve to workspace, videos/questions to store)
- update_manifest: key whitelist validation
- record_run: idempotent history append + per-video wiki dirs
- read_best / update_best: best pointer independent of current
- list_video_ids: videos with tree.json
- archive_workspace: move to .archive/<name>-<ts>
- VersionedSkillStore: implements core/evolution/protocols.py::SkillStore
- VersionedPromptStore: implements core/evolution/protocols.py::PromptStore
- 21 tests all passing (incl. Protocol compliance checks)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:41:59 -04:00
iomgaa b052c1f3ee feat(harness): store.py — Store 版本操作 + Seed 管理
从 TRM4 core/workspace.py 拆出 Store + Seed 相关函数:
- _parse_version / list_versions / next_version / advance_version
- _write_meta / init_store
- init_seed / list_seeds / read_seed
- extract_run_db(保留原始 CREATE 语句重建主键约束)
- promote_to_seed(强校验版本一致 + 非 NULL + finally 清理)

26 个测试全部通过,radon 复杂度 A (2.83)。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:36:36 -04:00
iomgaa be3c176a46 feat(harness): HarnessLog SQLite wrapper + RunLogImpl readonly port
- HarnessLog: TRM4 direct port with WAL mode, threading.Lock, INSERT OR
  IGNORE idempotent _runs, context manager (completed/failed), create_table
  with auto run_id+timestamp, insert/insert_many/execute/query/log_event
- RunLogImpl: implements core/evolution/protocols.py::RunLog Protocol with
  independent sqlite3.connect for read-only SELECT (no _runs pollution),
  asyncio.to_thread wrapping for async interface
- _read_table: shared readonly helper with optional question_ids filtering,
  graceful empty-list return for missing tables
- Tests: 17 cases covering thread safety, idempotent inserts, context
  manager status, WAL mode, protocol compliance, readonly isolation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:29:29 -04:00
iomgaa b929a5db6c fix(harness): Codex functional review 修复 — 命名/集成测试/delta_min/promote 消息
- _apply_env_overrides → _apply_env_var_overrides,docstring 明确从 os.environ 读取
- 新增 TestLoadConfigRealYaml:用真实 config/default.yaml 验证嵌套 harness 解析
- 新增 test_delta_min_negative_rejected:覆盖 gate_delta_min >= 0 校验
- 恢复 promote 模式独立错误消息(从合并分支分离回 TRM4 原始提示)
- 77 个单元测试全部通过,radon 全部 Grade B 或更好

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:23:27 -04:00
iomgaa ce43871828 fix(harness): 补充 train 模式 run_id 校验 + 拆分函数保持 radon Grade B
- _validate_mode_deps: 恢复 train 非 resume/fresh 时必须提供 run_id 校验
- 提取 _validate_train_run_id 用 early return 展平条件,避免 radon Grade C
- 合并 promote run_id 检查到 diagnose/evolve/promote 统一检查
- 新增 4 个测试:train+run_id / train+resume / train+fresh / train+baseline
- radon cc -n C 无输出(全部 Grade B 或更好)
- 74 个单元测试全部通过

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:14:28 -04:00
iomgaa 6a2ddb1624 refactor(harness): 拆分校验函数降低 radon 圈复杂度至 Grade B
- _validate: 拆出 _validate_mode(mode 依赖校验)+ _validate_basic(标量/枚举校验)
- _validate_gate: 拆为 _validate_gate_thresholds(e 值/净胜/方向)+ _validate_gate_ladder(阶梯/块序贯)
- load_config: 提取 _apply_env_overrides 函数
- radon cc -n C 无输出(全部 Grade B 或更好)
- 70 个单元测试全部通过

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 12:01:46 -04:00
iomgaa 09a385addc feat(harness): RunConfig frozen dataclass + 四层校验 + YAML/CLI/.env 三层加载
- RunConfig: 46 字段 frozen dataclass,从 TRM4 core/harness/config.py 迁移
- 四层校验链:_validate → _validate_edit_budget + _validate_minibatch + _validate_gate
- 新增 .env 覆盖层:工程配置(workspace_dir, store_dir)可通过 HARNESS_* 环境变量注入
- 合并优先级:CLI > .env > YAML(CLAUDE.md §4.5)
- load_config 支持嵌套 harness 段和扁平 YAML 两种格式
- run_id 改为默认空字符串(CLI-only 字段,YAML 不提供)
- resume/fresh 互斥校验不在 config 层(移至 runner.py)
- 70 个单元测试全部通过

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 11:57:35 -04:00
iomgaa 499c5b8043 feat(search): __init__.py 公开 API + 修复 OCR 测试 asyncio 兼容性 2026-07-07 06:13:25 -04:00
iomgaa 4baf92c93f feat(search): PromptManager — 搜索 Agent 提示词加载与组装
从 TRM4 core/search/prompt.py 迁移。有意变更:
- 工具描述从 app.search.tools.get_tool_descriptions 获取
- format_user_prompt 参数显式化(question/options/l1_node_ids/task_type)

16 个单元测试覆盖 __init__、build_inference_prompt(auto/manual/none
三种 skill_mode)、format_user_prompt、load。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 06:11:13 -04:00
iomgaa f4f92b0938 feat(search): 实现 SearchToolDispatcher 工具调度器 (Task 7)
- 新增 app/search/tools.py:
  - get_tool_descriptions() 工具描述文本(与 TRM4 一致)
  - SearchToolDispatcher 类实现 ToolDispatcher Protocol
  - dispatch() 按工具名路由: view_node / search_similar /
    observe_frame / submit_answer / read_skill
  - ValueError(未知工具)上抛,KeyError/FileNotFoundError 捕获返回错误文本
  - view_node: env.get_node_text + summarize_node + get_children_info + summarize_children
  - search_similar: env.search_similar + summarize_nodes_batch
  - observe_frame: env.resolve_frame_paths + get_subtitle + observe_frame + 字幕前置

- 修复 app/tree/environment.py get_children_info():
  - 原实现返回 _format_time_range (str) 导致 summarize_children 解包失败
  - 改为返回原始数值元组 via 新增 _node_time_range_raw 静态方法

- 新增 tests/unit/test_search_tools.py (14 tests):
  - get_tool_descriptions 含/不含 read_skill
  - 五种工具 dispatch 路由验证
  - 未知工具 ValueError + 节点不存在错误文本

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 06:07:27 -04:00
iomgaa ca3ea1cdf2 style: format summarizer.py 2026-07-07 05:55:40 -04:00
iomgaa ba7fdaddf6 style: format vision.py 2026-07-07 05:53:33 -04:00
iomgaa 3ae3d5ab50 feat(search): app/search/vision.py — 两轮 VLM 帧观察模块
从 TRM4 core/tree/vision.py 迁移 observe_frame,关键变更:
- VLM 调用走 VLMProvider.chat_with_images Protocol(images 传 Path)
- OCR 调用走 OCRProvider.transcribe_frames 异步 Protocol
- 遥测字段 session_id / parent_call_id 透传
- 帧文件存在性前置校验

12 个单元测试覆盖:两轮正常、仅提取、OCR 注入/失败降级/None、
VLM 提取失败、VLM 验证失败降级、帧缺失、stats 完整性、
分歧/弃权标记、遥测透传。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 05:52:54 -04:00
iomgaa 86b19d1e07 feat(adapters): OCRProvider Protocol + MonkeyOCRClient 异步适配器
- app/ports.py: 新增 OCRProvider Protocol(runtime_checkable,与
  EmbeddingProvider 同级),定义 async transcribe_frames 端口
- adapters/ocr.py: 从 TRM4 core/tree/ocr.py 保真迁移 MonkeyOCRClient
  - assert → ValueError(P5 防御性校验)
  - 公开方法改 async(asyncio.to_thread 包装同步 HTTP)
  - 内部逻辑不变:多端点轮询、线程安全 Session、单帧降级、行去重
- tests/unit/test_ocr_adapter.py: 17 个测试覆盖 Protocol 合规、
  构造校验、健康检查、转录、降级、去重、轮询

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 05:47:55 -04:00
iomgaa 60e737e2fc feat(search): app/search/skills.py — 技能注册表与 frontmatter 解析
从 TRM4 core/search/skills.py 保真迁移。提供 parse_frontmatter、
strip_frontmatter、SkillRegistry、discover_skills 四个公共 API。
逻辑完全一致,仅调整导入路径并添加中文 docstring。

17 个单元测试全部通过,覆盖正常/异常/边界场景。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 05:46:25 -04:00
iomgaa 82f1607195 style: format environment.py 2026-07-07 05:46:25 -04:00
iomgaa 44ee62867d feat(tree): add get_node_text + get_children_info to TreeEnvironment
- get_node_text(node_id, anchor=False): returns raw text + optional
  anchor_map dict by parsing [cN]/[sN] prefixes from anchored text
- get_children_info(node_id): returns structured child list with
  id/time_range/summary (description truncated to 120 chars)
- Both methods reuse existing internal helpers (_node_full_text,
  _node_anchored_text, _get_children, _node_description,
  _format_time_range)
- 9 new test cases across TestGetNodeText and TestGetChildrenInfo

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 05:45:48 -04:00
iomgaa d8a903fb54 feat(question_gen): QuestionGenerator Protocol + 模块公开 API
app/ports.py 追加 QuestionGenerator Protocol(预留 LLM 出题接口)。
app/question_gen/__init__.py re-export load_benchmark 和 stratified_sample。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 04:48:21 -04:00
iomgaa 8d515ff01f feat(question_gen): stratified_sample — 分层采样 + 题型保底
算法 100% 保真 TRM4: task_types 过滤、correctness.get(id, False) 语义、
对题在前返回顺序、min_per_class 遍历 pool 全部题型(含稀疏类)。
所有参数显式传入,无默认值。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 04:45:19 -04:00
iomgaa dea8a7d3f6 feat(question_gen): load_benchmark — benchmark JSON 加载
从 JSON 目录 glob *.json 加载题目,stem 作 video_id。
legacy schema 无 difficulty 字段时赋 _LEGACY_DEFAULT_DIFFICULTY 常量。
options/source_nodes 转 tuple 配合 frozen dataclass。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 04:41:25 -04:00
iomgaa 4686adf266 feat(tree/repair): 检测器扩展 — visible_entities/ongoing_actions/spatial_layout 为空也触发修复 2026-07-07 03:15:42 -04:00
iomgaa 18971a794b feat(tree/repair): Q&A 反向补全 — 从 TRM4 supplement 迁移
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 02:37:50 -04:00
iomgaa edaa0d8290 feat(tree): VideoTreeBuilder 保真 #1 #2 #3 + 复杂度重构
- 从 reference/video_tree_trm/video_tree_builder.py (994行) 迁移
- 保真算法 #1: L2 轴心建树策略 (asyncio.gather 链式并发)
- 保真算法 #2: VLM 批量帧描述 + JSON fallback (_L3_BATCH_SIZE=5)
- 保真算法 #3: 断点续跑 (progress.json + L1 中间 JSON)
- 新增: VLMProvider/LLMProvider Protocol 替代 LLMClient
- 新增: 结构化 JSON 输出 → L1Card/L2Card/L3Card
- 新增: L2 代表帧复用 L3 帧 (_sample_representative_frames)
- 新增: 字幕注入 + Voronoi 分配
- 重构: 提取 _load_resume_state/_assemble_roots 降低 _build_async 复杂度 D(21)→C(14)
- 44 个单元测试全部通过

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 02:17:50 -04:00
iomgaa 12f20493c1 feat(tree): 质量校验 — 交叉验证 entities/visible_text
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:57:32 -04:00
iomgaa fb6f9964d8 feat(tree): 字幕模块 — SRT 解析 + 完整性检查 + Voronoi 分配
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:54:09 -04:00
iomgaa c1680447c0 feat(adapters): EmbeddingProvider Protocol + local/remote 双后端实现
- app/ports.py: 添加 EmbeddingProvider Protocol(runtime_checkable,dim 属性 + embed 方法)
- adapters/embedding.py: 从参考代码迁移,拆分为 LocalEmbeddingProvider 和 RemoteEmbeddingProvider
  - Local: sentence-transformers 冻结推理,维度校验
  - Remote: OpenAI 兼容 API,L2 归一化,按 index 排序
  - 两者均提供 embed() 和 embed_tensor() 统一接口
- tests/unit/test_embedding_adapter.py: Protocol 满足性、形状校验、导入测试

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:45:09 -04:00
iomgaa 547c9ddd84 feat(tree): TreeConfig 配置 dataclass
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:41:50 -04:00
iomgaa e0f7851975 fix(tree): from_dict 增加 ID 唯一性校验
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:40:46 -04:00
iomgaa c136de076d refactor(tree): extract _embed_l2_subtree to reduce embed_all complexity
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:37:09 -04:00
iomgaa 22ad014973 feat(tree): TreeIndex 数据结构 — Card 体系 + 节点 + 序列化
- 新增三级 frozen Card dataclass: L3Card(6字段), L2Card(7字段), L1Card(7字段)
- 节点重构: L3Node/L2Node/L1Node 使用 Card 替代原始字符串字段
- 添加 @property 兼容层: description/summary 代理到 Card 字段
- L3Node 新增 subtitle 字段(字幕集成预留)
- JSON 序列化/反序列化支持 Card 结构 + embedding base64 编解码
- load_json 新增 ID 唯一性校验(重复 ID 抛 ValueError)
- 移除 pickle 序列化(仅保留 JSON)
- 日志从 log_msg 迁移到 loguru
- 17 个单元测试全部通过

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-07 01:35:10 -04:00
iomgaa e60823de1a build: add README, pyproject.toml, package skeletons and smoke test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-06 11:37:59 -04:00