fix: 批量匹配跳过画像待补录教师 + render-html 按行重建 + 金标准 fixtures 业务化(P0+P1)

- run_match 新增 skip_incomplete:批量缺省跳过画像不完整教师并记录 skipped,指定单教师仍 PROFILE_INCOMPLETE;汇总页出"画像待补录"行
- render-html 补 --report-id 行上下文(inputMapping $row.$pk),CLI 容错解析回退最近 10 份
- report_service 日志改容错 _log(),修复未 setup 时单跑测试崩溃的顺序依赖
- fixtures 替换为教师画像/赛道/期望结论金标准样例,新增 sample_tracks.json
- 新增 4 个批量跳过用例(314 项,除 3 个已知 jsonschema 环境失败外全绿)
- tests/README 增补本机无共享 runtime 的测试方式;TUTORIAL/ACTIONS.md 同步表述
This commit is contained in:
chenfuqiang
2026-09-24 18:01:41 +08:00
parent 7c1f40b0e6
commit 4a8613b27e
15 changed files with 267 additions and 47 deletions

View File

@@ -485,7 +485,9 @@ def cmd_match(*, teacher: str = "", year: Optional[int] = None) -> int:
return 1
season = str(year or tracks[0].get("year") or "")
result = run_match(teachers, tracks, season)
# 指定教师 → 严格模式,画像不完整直接 PROFILE_INCOMPLETE;
# 缺省全量 → 跳过画像待补录教师并记录,不中断批次(E1)。
result = run_match(teachers, tracks, season, skip_incomplete=not teacher)
payload = {k: v for k, v in result.items() if k != "reports"}
payload["reports_brief"] = [
{
@@ -499,9 +501,14 @@ def cmd_match(*, teacher: str = "", year: Optional[int] = None) -> int:
for r in result["reports"]
]
_print_json(payload)
skipped_count = len(result.get("skipped") or [])
message = f"匹配完成 {result['count']} 名教师,建议书已生成"
if skipped_count:
message += f";{skipped_count} 名教师画像待补录已跳过"
log.info("match_skipped count=%s stage=match", skipped_count)
finish(
status="success",
message=f"匹配完成 {result['count']} 名教师,建议书已生成",
message=message,
skill=SKILL_SLUG,
stage="match",
batch_no=result["batch_no"],
@@ -568,7 +575,7 @@ def cmd_match_batch_input() -> int:
return 1
season = str(tracks[0].get("year") or "")
result = run_match(teachers, tracks, season)
result = run_match(teachers, tracks, season, skip_incomplete=True)
for index, report in enumerate(result["reports"], start=1):
top = (report.get("top3") or [{}])[0]
emit(
@@ -577,16 +584,27 @@ def cmd_match_batch_input() -> int:
skill=SKILL_SLUG,
stage="batch",
)
for entry in result.get("skipped") or []:
emit(
f"{entry.get('teacher_name')}:画像待补录,本期已跳过({entry.get('reason')})",
type="warn",
skill=SKILL_SLUG,
stage="batch",
)
_print_json(
{
"ok": True,
"batch_no": result["batch_no"],
"count": result["count"],
"skipped": result.get("skipped") or [],
"tier_counts": result["tier_counts"],
"brief_file": result["brief_file"],
}
)
finish(status="success", message=f"批量匹配完成 {result['count']} 名教师", skill=SKILL_SLUG, stage="batch", batch_no=result["batch_no"])
message = f"批量匹配完成 {result['count']} 名教师"
if result.get("skipped"):
message += f",{len(result['skipped'])} 名画像待补录已跳过"
finish(status="success", message=message, skill=SKILL_SLUG, stage="batch", batch_no=result["batch_no"])
return 0
except JobStopped:
raise