release: v0.20 Codex-ready skill-driven core
This commit is contained in:
+172
-1
@@ -1,4 +1,4 @@
|
||||
"""Deterministic Phase 3 review checks for the Python core."""
|
||||
"""Phase 3 review checks for the Python core."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -52,6 +52,24 @@ def _ready_packet_stems(project_root: Path) -> set[str]:
|
||||
return ready
|
||||
|
||||
|
||||
def _read_text_if_exists(path: Path, *, max_chars: int | None = None) -> str:
|
||||
if not path.exists():
|
||||
return ""
|
||||
text = path.read_text(encoding="utf-8", errors="ignore")
|
||||
return text[:max_chars] if max_chars is not None else text
|
||||
|
||||
|
||||
def _json_if_exists(path: Path, *, max_chars: int | None = None) -> str:
|
||||
if not path.exists():
|
||||
return ""
|
||||
try:
|
||||
data = json.loads(path.read_text(encoding="utf-8"))
|
||||
text = json.dumps(data, ensure_ascii=False, indent=2)
|
||||
except Exception:
|
||||
text = path.read_text(encoding="utf-8", errors="ignore")
|
||||
return text[:max_chars] if max_chars is not None else text
|
||||
|
||||
|
||||
def _draft_quality_findings(drafts: list[Path]) -> list[dict[str, Any]]:
|
||||
findings: list[dict[str, Any]] = []
|
||||
generic_markers = [
|
||||
@@ -77,6 +95,159 @@ def _draft_quality_findings(drafts: list[Path]) -> list[dict[str, Any]]:
|
||||
return findings
|
||||
|
||||
|
||||
def build_phase3_model_review_context(project_root: Path, *, max_chars: int = 650_000) -> str:
|
||||
"""Build a structured, bounded context packet for an independent model review."""
|
||||
deterministic_path = build_phase3_critique(project_root)
|
||||
deterministic_copy = project_root / "phase3" / "critique_deterministic.md"
|
||||
deterministic_copy.write_text(deterministic_path.read_text(encoding="utf-8"), encoding="utf-8")
|
||||
|
||||
manifest = load_manifest(project_root)
|
||||
parts: list[str] = [
|
||||
f"# Phase 3 Model Review Context: {manifest.get('topic', project_root.name)}",
|
||||
"",
|
||||
"## Review Contract",
|
||||
"",
|
||||
"- 这是给非 Codex 模型的独立总编审校上下文,不要求重写正文。",
|
||||
"- 请判断 Phase2 草稿能否进入 Phase4,或必须回炉补证据/重写。",
|
||||
"- 重点关注:证据是否落纸面、并发 packet 是否造成碎片化、法规/最佳实践覆盖是否足够、整改建议是否具体可执行。",
|
||||
"",
|
||||
"## Manifest",
|
||||
"",
|
||||
"```json",
|
||||
json.dumps(manifest, ensure_ascii=False, indent=2),
|
||||
"```",
|
||||
"",
|
||||
"## Deterministic Review Baseline",
|
||||
"",
|
||||
_read_text_if_exists(deterministic_copy),
|
||||
"",
|
||||
"## Phase 1 Framework",
|
||||
"",
|
||||
_read_text_if_exists(project_root / "phase1" / "framework.md", max_chars=50_000),
|
||||
"",
|
||||
"## Phase 1 Research Brief",
|
||||
"",
|
||||
_read_text_if_exists(project_root / "phase1" / "research_brief.md", max_chars=30_000),
|
||||
"",
|
||||
"## Phase 2 Brief Warnings",
|
||||
"",
|
||||
_json_if_exists(project_root / "phase2" / "brief_warnings.json", max_chars=30_000) or "无",
|
||||
"",
|
||||
"## Phase 2 Packet Errors",
|
||||
"",
|
||||
]
|
||||
errors = sorted((project_root / "phase2" / "packet_errors").glob("*.json"))
|
||||
if errors:
|
||||
for path in errors[:40]:
|
||||
parts.extend([f"### {path.name}", "", _json_if_exists(path, max_chars=2_000), ""])
|
||||
else:
|
||||
parts.append("无")
|
||||
|
||||
parts.extend(["", "## Source Registry Summary", ""])
|
||||
source_lines = []
|
||||
sources_path = project_root / "phase2" / "sources.jsonl"
|
||||
if sources_path.exists():
|
||||
for line in sources_path.read_text(encoding="utf-8").splitlines()[:260]:
|
||||
if not line.strip():
|
||||
continue
|
||||
try:
|
||||
source = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
source_lines.append(
|
||||
"- {id} | {tier} | {title} | {url} | cached={cached}".format(
|
||||
id=source.get("id", ""),
|
||||
tier=source.get("tier", ""),
|
||||
title=str(source.get("title", ""))[:120],
|
||||
url=source.get("url", ""),
|
||||
cached=source.get("cached_text_path", ""),
|
||||
)
|
||||
)
|
||||
parts.append("\n".join(source_lines) or "无")
|
||||
|
||||
parts.extend(["", "## Compressed Findings", ""])
|
||||
for path in sorted((project_root / "phase2" / "compressed_findings").glob("ch*.json")):
|
||||
parts.extend([f"### {path.name}", "", "```json", _json_if_exists(path, max_chars=35_000), "```", ""])
|
||||
|
||||
parts.extend(["", "## Chapter Drafts", ""])
|
||||
for path in sorted((project_root / "phase2" / "drafts").glob("ch*.md")):
|
||||
parts.extend([f"### {path.name}", "", _read_text_if_exists(path, max_chars=55_000), ""])
|
||||
|
||||
context = "\n".join(parts)
|
||||
if len(context) > max_chars:
|
||||
context = context[:max_chars] + "\n\n[Context truncated by max_chars; review should flag if truncation limits confidence.]\n"
|
||||
|
||||
out = project_root / "phase3" / "review_context_opus_4_7.md"
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
out.write_text(context, encoding="utf-8")
|
||||
return context
|
||||
|
||||
|
||||
def phase3_model_review_system_prompt() -> str:
|
||||
return (
|
||||
"你是 Deep Research Phase 3 的独立总编审校模型,本次由 ZenMux Claude Opus 4.7 执行,用于避免 Codex/OpenAI 模型偏见。\n"
|
||||
"你的任务是审校,不是润色或重写。必须用中文输出,英文仅可保留 source title、URL、法规缩写和原文短摘录。\n"
|
||||
"请严格检查:1) 研究目标与 Phase1 框架是否契合;2) Phase2 并发 evidence packets 是否被章节真正吸收,还是造成碎片化;"
|
||||
"3) FDA/NMPA/EMA/ICH/WHO/EU GMP 等权威来源是否足以支撑关键判断;4) 用户材料是否被正确作为起点且被权威来源交叉验证;"
|
||||
"5) 运营管理与团队能力章节是否具体,不得泛泛咨询腔;6) CAPA 建议是否包含 owner、期限、关闭证据、QA verification、复核窗口和升级阈值;"
|
||||
"7) 引用链和 source_id 是否可追踪;8) 是否仍有明显 AI 味、中英文混杂或空泛表达。\n\n"
|
||||
"输出必须使用以下 Markdown 结构:\n"
|
||||
"# Phase 3 Opus 4.7 独立审校\n"
|
||||
"## 总体判定\n"
|
||||
"给出:通过 / 有条件通过 / 回炉 Phase2,并说明最核心理由。\n"
|
||||
"## P0/P1 阻断问题\n"
|
||||
"列出必须修复的问题;每条写明章节/文件、问题、为什么阻断、建议动作。\n"
|
||||
"## 章节级审校表\n"
|
||||
"用表格覆盖 ch01-ch11:主线质量、证据密度、法规覆盖、整改可执行性、是否需要回炉。\n"
|
||||
"## 证据与信源质量\n"
|
||||
"单独评价 FDA warning letters、ICH Q9/Q10、EU GMP Annex 1、本地缓存信源、第三方低质信源的使用情况。\n"
|
||||
"## 碎片化与叙事连贯性\n"
|
||||
"判断并发研究是否造成割裂,并给出具体整合建议。\n"
|
||||
"## Phase2 回炉任务清单\n"
|
||||
"如果需要回炉,列出可执行任务卡级别的补证据/重写要求。\n"
|
||||
"## Phase4 准入条件\n"
|
||||
"明确进入 final 前必须满足的条件。\n"
|
||||
)
|
||||
|
||||
|
||||
def build_phase3_model_critique(
|
||||
project_root: Path,
|
||||
*,
|
||||
client: Any,
|
||||
model: str = "zenmux-anthropic/claude-opus-4-7",
|
||||
max_context_chars: int = 650_000,
|
||||
) -> Path:
|
||||
context = build_phase3_model_review_context(project_root, max_chars=max_context_chars)
|
||||
content = client.chat_complete(
|
||||
model=model,
|
||||
system=phase3_model_review_system_prompt(),
|
||||
user=context,
|
||||
temperature=0.2,
|
||||
max_tokens=20_000,
|
||||
tag="phase3:opus-review",
|
||||
)
|
||||
out = project_root / "phase3" / "critique.md"
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
out.write_text(content.rstrip() + "\n", encoding="utf-8")
|
||||
|
||||
manifest = load_manifest(project_root)
|
||||
phase3 = manifest.setdefault("phase3", {})
|
||||
phase3.update(
|
||||
{
|
||||
"status": "completed",
|
||||
"review_mode": "model",
|
||||
"review_model": model,
|
||||
"critique_path": "phase3/critique.md",
|
||||
"context_path": "phase3/review_context_opus_4_7.md",
|
||||
"deterministic_critique_path": "phase3/critique_deterministic.md",
|
||||
"updated_at": utc_now_iso(),
|
||||
}
|
||||
)
|
||||
manifest["updated_at"] = utc_now_iso()
|
||||
write_manifest(project_root, manifest)
|
||||
return out
|
||||
|
||||
|
||||
def build_phase3_critique(project_root: Path) -> Path:
|
||||
manifest = load_manifest(project_root)
|
||||
drafts = sorted((project_root / "phase2" / "drafts").glob("ch*.md"))
|
||||
|
||||
Reference in New Issue
Block a user