Files
dafang bb7c22829f feat(cs-epic): add parallel item progression policy
Add item_progression: parallel as an owner-gated scheduling extension:
the main workflow stays the sole orchestrator and cursor writer, workers
execute dependency-independent items in host-provided isolated
workspaces, and integration is serialized without advancing mainline
history until per-item re-verification passes. Ships the parallel
execution protocol reference (wavefront scheduling, contextPacket
delegation, active_items recovery records with branched state
transitions, item-local vs epic-global blockers, capability fallback),
mirrors the contract across bilingual WORKFLOW/CATALOG, ADR-005,
AGENTS.md and CLAUDE.md, and anchors it in the contract tests.

Reviewed by an independent heterogeneous reviewer over three rounds
(final verdict: approve; target sha256 a78d424e1d3a).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 10:09:31 +08:00

1241 lines
53 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""CodeStable skills 的直接语义守卫与 routing fixture 回归。"""
from __future__ import annotations
from pathlib import Path
import yaml
ROOT = Path(__file__).resolve().parents[1]
SKILLS = ROOT / "plugins/codestable/skills"
# 工具 skillauthoring/eval不随插件交付也必须使用标准 frontmatter。
LOCAL_SKILLS = ROOT / ".claude/skills"
TASK_SKILLS = ("cs-feat", "cs-issue", "cs-refactor", "cs-epic")
ORDINARY_TASK_SKILLS = ("cs-feat", "cs-issue", "cs-refactor")
MINIMUM_SUFFICIENT_ASSURANCE_CONTRACT = (
"执行流程 = 最小闭环 + 每个未排除风险所要求的最少保障",
"一次静默、有界核对",
"不能排除时先按风险存在处理",
"不得以“没有注意到风险”作为降级依据",
"风险事实 → 增加的保障",
"一个风险只增加与它直接对应的保障",
"不自动启用整套 design、全量回归、独立 review、work 文档或 Epic final acceptance 路径",
"行数、文件数、文案/代码类型和 task kind 都不是风险的替代指标",
"流程太重 / 只是小改动 / 文档比代码多",
"不是无条件跳过安全门槛",
"停止继续增加产物并重算",
)
LEGACY_KNOWLEDGE_DIRS = {
".codestable/roadmap/",
".codestable/features/",
".codestable/issues/",
".codestable/refactors/",
".codestable/goals/",
".codestable/compound/",
".codestable/audits/",
".codestable/brainstorms/",
".codestable/feedback/",
}
LESSON_READ_REPAIR_CONTRACT = {
"经验命中:{path}{status});核验:{fact};影响:{plan_or_check}",
"旧 lesson 缺 `status` 按 `observed` 读取",
"`retired` 不应用",
"`observed` / `validated` 先核实再用",
"只做一次有界、最低成本的定向核实",
"不得仅为核实 lesson 运行大范围测试或反复复现",
"仍不足时跳过该 lesson不阻塞正常任务",
"只是相关但没有改变行为时不制造复用证据",
"明确排除一个具体且合理的错误路径",
"当前事实明确反证时立即停止应用",
"证据不足时不猜",
}
CRYSTALLIZATION_SIGNAL_CONTRACT = {
"任务内只在内存保留最多 3 条候选",
"不暂停或询问",
"owner 纠正实际改变方案/代码/术语/验证",
"可复现证据推翻根因",
"同一路径失败两次后更换假设",
"blocking/important finding 暴露未编码不变量",
"新 red -> green 捕获可复发失败",
"lesson 真实改变本次行为或被反证",
"重复 workaround",
"方法显著降低重试、成本或风险",
"可追溯证据",
"能写成未来动作",
"本次精确 diff 之外",
"没有现成 canonical owner",
"网络波动、拼写、泛化口号、活动记录",
"已被机械 owner 完整覆盖",
}
NARROW_LESSON_MAINTENANCE_CONTRACT = {
"仅对已有且有效命中的 lesson",
"`observed -> validated`",
"独立后续任务确实采用并验证成功",
"只补一次代表性证据",
"必须记录 lesson 实际改变的计划或验证",
"本次通过的验收证据",
"`observed|validated -> retired`",
"当前仓库事实直接反证",
"发现已有 canonical owner",
"只写原因与替代/反证指针",
"不新建事实",
"不改规则",
"不扩 scope",
"不新增 gate",
"稳定 validated 命中不写文件",
"需要改写结论或证据不足时只给候选",
"新结论不得通过复活 retired 条目",
"最终报告列出文件变化",
}
THIN_SKILL_SAFETY_INVARIANTS = {
"cs": (
"同轮直转",
"只推荐入口",
"导览与推荐本身不写任何文件",
"讨论只存在于当前会话",
"不创建 `.codestable/work/discussion-*`",
),
"cs-review": (
"只读",
"叶子执行器",
"禁止创建、委派或唤醒任何子 agent",
"不得再次调用 `cs-review`",
"不保存复审轮次",
"blocking 未解决",
),
"cs-code-review": (
"兼容别名",
"canonical entry `cs-review`",
"不得读取 sibling skill 文件",
),
"cs-epic": (
"拆解方案必须经用户确认",
"由当前主流程创建一个 fresh reviewer",
"本轮失败且不计轮次",
"不得盲目重发",
"不代替用户做整体验收",
),
"cs-feat": (
"不得代替用户确认设计",
"由当前主流程创建一个 fresh reviewer",
"本轮失败且不计轮次",
"不得盲目重发",
"与声明相称的可核验证据",
),
"cs-issue": (
"能明确变红的验证",
"变红的验证必须变绿",
"由当前主流程创建一个 fresh reviewer",
"本轮失败且不计轮次",
"不得盲目重发",
),
"cs-keep": ("没有可追溯证据不写", "`.codestable/compound/` 是只读历史知识源"),
"cs-onboard": ("存量文件一律不动", "不复制"),
"cs-refactor": (
"行为等价",
"先有能自证等价的验证",
"由当前主流程创建一个 fresh reviewer",
"本轮失败且不计轮次",
"不得盲目重发",
),
}
THIN_SKILL_FORBIDDEN_TEXT = {
"cs": ("L0-L4",),
"cs-review": (
"git push",
"read all references",
"用独立 subagent reviewer",
"派发 reviewer 时",
"探测全部已配置的审查 agent/model",
"累计最多 3 轮",
),
"cs-code-review": ("按 `cs-review` 的 SKILL.md 执行",),
"cs-epic": ("ConfirmGoalCommitAuthorization", "git push", "read all references"),
"cs-feat": ("git push", "read all references"),
"cs-issue": ("git push", "read all references"),
"cs-refactor": ("git push", "read all references"),
}
ISSUE_DIAGNOSIS_CONTRACT = (
"用户只要求定位、分析、解释或排查时,执行只诊断",
"诊断结论不扩大为修复授权",
"不改产品代码、测试或配置,不创建 commit",
"diagnose 不新增审查阶段",
"`已证实根因` / `可证伪假设` / `证据不足`",
"至少实际运行一次",
"可再次执行的命令及红色输出",
"手工复现步骤及失败观察",
"diagnose 下“优先失败测试”指优先运行既有失败或只读检查",
"同一失败信号",
"那条变红的验证必须变绿",
"无法建立时列明已尝试",
"日志、trace、环境访问",
"临时 harness、日志或埋点",
"先停下说明目标、路径、影响与清理方式",
"同会话直接授权修复不算诊断终止",
"核对工作树与仓库外临时路径",
"残留文件与保留理由",
"单独 change candidate",
)
ISSUE_DEBUG_REFERENCE_CONTRACT = (
"覆盖用户实际症状",
"出现任一才升级,不默认升级",
"3-5 个排序的可证伪假设",
"一次只动一个变量",
"自动化二分",
"提高并报告复现率",
"性能问题先建立可比较的性能基线",
"正确接缝",
"前缀或等价标签",
"定向搜索证明已移除",
"最小场景",
"原始完整复现",
)
def _read_skill(path: Path) -> tuple[dict[str, object], str]:
text = path.read_text(encoding="utf-8")
assert text.startswith("---\n"), path
_, frontmatter, body = text.split("---\n", 2)
return yaml.safe_load(frontmatter), body
def _contains_contract(text: str, anchor: str) -> bool:
return "".join(anchor.split()) in "".join(text.split())
def test_active_skills_do_not_use_legacy_frontmatter_contracts() -> None:
for root in (SKILLS, LOCAL_SKILLS):
for path in sorted(root.glob("*/SKILL.md")):
frontmatter, _ = _read_skill(path)
assert "contracts" not in frontmatter, path
def test_thin_skills_keep_explicit_safety_invariants() -> None:
active_skills = {path.parent.name for path in SKILLS.glob("*/SKILL.md")}
assert set(THIN_SKILL_SAFETY_INVARIANTS) == active_skills
for skill_name, invariants in THIN_SKILL_SAFETY_INVARIANTS.items():
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
for invariant in invariants:
assert invariant in body, f"{skill_name}: missing {invariant!r}"
for skill_name, forbidden_texts in THIN_SKILL_FORBIDDEN_TEXT.items():
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
for forbidden in forbidden_texts:
assert forbidden not in body, f"{skill_name}: forbidden {forbidden!r}"
review_openai = yaml.safe_load(
(SKILLS / "cs-review/agents/openai.yaml").read_text(encoding="utf-8")
)
review_frontmatter, _ = _read_skill(SKILLS / "cs-review/SKILL.md")
review_prompt = review_openai["interface"]["default_prompt"]
assert str(review_frontmatter["description"]).startswith("只读审查叶子执行器")
assert "$cs-review" in review_prompt
assert "不创建任何子 agent" in review_prompt
assert "独立" not in review_openai["interface"]["short_description"]
assert "独立" not in review_prompt
assert "派发独立 subagent reviewer" not in review_prompt
def test_cs_issue_owns_diagnosis_and_authorized_fix_modes() -> None:
frontmatter, issue = _read_skill(SKILLS / "cs-issue/SKILL.md")
debug = (SKILLS / "cs-issue/references/debug.md").read_text(encoding="utf-8")
_, cs = _read_skill(SKILLS / "cs/SKILL.md")
assert str(frontmatter["description"]).startswith("诊断或修复 bug、报错、性能回退")
for anchor in ISSUE_DIAGNOSIS_CONTRACT:
assert _contains_contract(issue, anchor), f"cs-issue: missing {anchor!r}"
for anchor in ISSUE_DEBUG_REFERENCE_CONTRACT:
assert _contains_contract(debug, anchor), f"debug reference: missing {anchor!r}"
shipped_issue = issue + debug
assert "diagnosing-bugs" not in shipped_issue
assert "排查这个报错为什么发生" in cs
assert "排查、诊断、bug、报错、性能回退、行为异常" in cs
refactor_frontmatter, refactor = _read_skill(SKILLS / "cs-refactor/SKILL.md")
assert "行为等价" in refactor
assert "性能优化" in str(refactor_frontmatter["description"])
def test_cs_discusses_in_session_then_hands_off_same_turn() -> None:
_, cs = _read_skill(SKILLS / "cs/SKILL.md")
for anchor in (
"用户显式要求先讨论",
"默认优先级最高",
"产品决策会实质改变建档或改代码路径",
"讨论只存在于当前会话",
"仓库可核实的事实由 agent 自行调查",
"一次只问一个真正需要 owner 决定的问题",
"目标入口、原始诉求、目标或期望行为、范围、非目标、验收口径",
"已核实仓库事实及来源",
"owner 已确认的术语与决策",
"已有执行授权时同轮移交",
"不再询问“是否继续”",
"讨论过程本身不产生授权",
"不创建 `.codestable/work/discussion-*`",
"未收敛讨论不跨会话恢复",
"三个已确认出口",
"不附带 handoff 的不重复确认契约",
"原始问答、未决讨论和候选分支不落盘",
"canonical 术语归宿",
"难逆转、缺少上下文会令人意外且源于真实取舍",
"永久 Epic 文档",
"`attention.md`",
"`lessons/`",
):
assert anchor in cs
work = ROOT / ".codestable/work"
assert not any(path.name.startswith("discussion-") for path in work.glob("*.md"))
assert not (SKILLS / "cs-align").exists()
def test_confirmed_cs_handoff_avoids_duplicate_intake_without_expanding_authority() -> None:
handoff_owners = ("cs-feat", "cs-issue", "cs-epic")
for skill_name in handoff_owners:
_, owner = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in (
"同一会话由 `cs` 交入且带已确认 handoff",
"packet 精确范围内已确认的事项不重复询问",
"owner 已确认的术语与决策",
"canonical 资产指针或资产候选",
"仓库事实冲突",
"会改变结果的新风险",
"缺少会改变方向的事实",
"超出已确认边界",
"不扩大实现、commit、发布或写入授权",
"不替代本 skill 的 review、验证与确认门槛",
):
assert anchor in owner, skill_name
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
assert "handoff 只用于起草 proposed 永久 Epic 文档" in epic
assert "不替代 fresh design review、批准 hash 或第一道 owner gate" in epic
_, refactor = _read_skill(SKILLS / "cs-refactor/SKILL.md")
assert "同一会话由 `cs` 交入且带已确认 handoff" not in refactor
def test_shared_language_contract_is_published_across_discussion_feature_epic_and_review() -> None:
_, cs = _read_skill(SKILLS / "cs/SKILL.md")
_, feat = _read_skill(SKILLS / "cs-feat/SKILL.md")
feat_language = (SKILLS / "cs-feat/references/shared-language.md").read_text(
encoding="utf-8"
)
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
epic_language = (SKILLS / "cs-epic/references/shared-language.md").read_text(
encoding="utf-8"
)
wayfinding = (SKILLS / "cs-epic/references/wayfinding.md").read_text(
encoding="utf-8"
)
_, review = _read_skill(SKILLS / "cs-review/SKILL.md")
assert "共享语言只在歧义会改变目标、行为、归属、契约或验收时收敛" in cs
assert "已有单义术语不增加提问或产物" in cs
assert "references/shared-language.md" in feat
assert _contains_contract(feat, "共享语言分支与完整 design 独立触发")
assert "写入现有交付摘要,不为术语另建 artifact" in feat
assert "写入既有 work 游标的 `边界` 节,不为术语新建 work" in feat
for anchor in (
"普通改动沿用已有单义词汇时跳过",
"canonical 名称、紧凑定义、排除含义和一个边界场景",
"不自动创建 `CONTEXT.md`",
"实现、API、schema、文档与测试使用同一含义",
):
assert _contains_contract(feat_language, anchor), anchor
assert "references/shared-language.md" in epic
assert _contains_contract(epic, "可判定的 Language Clear 条件")
permanent = epic.split("永久文档最小结构", 1)[1].split(
"work 游标最小结构", 1
)[0]
cursor = epic.split("work 游标最小结构", 1)[1].split(
"永久 `status`", 1
)[0]
assert "## 共享语言与概念边界" in permanent
assert "## 共享语言与概念边界" not in cursor
for anchor in (
"术语歧义不新增状态",
"仓库事实走 `AFK`",
"产品含义或概念边界走 `HITL`",
"一条具体的端到端或边界场景",
"不自动创建 `CONTEXT.md`",
"不是新的 owner gate",
):
assert _contains_contract(epic_language, anchor), anchor
assert "术语歧义" in wayfinding
assert "会改变路线的术语已经单义化" in wayfinding
for anchor in (
"design / contract review",
"先定义后使用",
"同一术语全文同义",
"不能替 owner 证明理解",
"已有单义术语或纯实现细节不要求新增 glossary",
):
assert _contains_contract(review, anchor), anchor
def test_task_skills_retrieve_legacy_knowledge_read_only() -> None:
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
kickoff = body.split("## 开工", 1)[1].split("\n## ", 1)[0]
found = {
path for path in LEGACY_KNOWLEDGE_DIRS if f"`{path}`" in kickoff
}
assert found == LEGACY_KNOWLEDGE_DIRS, skill_name
assert "关键词" in kickoff, skill_name
assert "检索" in kickoff or "grep" in kickoff, skill_name
assert "只读" in kickoff, skill_name
assert "命中要报告来源路径" in kickoff, skill_name
assert "不得继续生成" in kickoff, skill_name
assert "原地改写" in kickoff, skill_name
assert "批量迁移" in kickoff, skill_name
def test_task_skills_share_the_complete_lesson_read_repair_contract() -> None:
signatures = {}
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
signatures[skill_name] = {
anchor
for anchor in LESSON_READ_REPAIR_CONTRACT
if _contains_contract(body, anchor)
}
assert len({frozenset(signature) for signature in signatures.values()}) == 1
for skill_name, signature in signatures.items():
assert signature == LESSON_READ_REPAIR_CONTRACT, skill_name
def test_task_skills_share_the_bounded_strong_signal_contract() -> None:
signatures = {}
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
signatures[skill_name] = {
anchor
for anchor in CRYSTALLIZATION_SIGNAL_CONTRACT
if _contains_contract(body, anchor)
}
assert len({frozenset(signature) for signature in signatures.values()}) == 1
for skill_name, signature in signatures.items():
assert signature == CRYSTALLIZATION_SIGNAL_CONTRACT, skill_name
def test_crystallization_closing_is_quiet_and_prefers_mechanical_guards() -> None:
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in (
"当前任务范围内能直接落成 red -> green 测试/checker",
"优先机械化",
"不另写重复 lesson",
"会扩大范围时只给候选",
):
assert _contains_contract(body, anchor), skill_name
for skill_name in ORDINARY_TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in (
"普通任务只在强信号成立时展示最高价值一条",
"`晶化候选:{rule}`",
"证据、范围和建议归宿",
"无强信号完全不显示模板",
"没有记忆写入授权时不落盘",
):
assert _contains_contract(body, anchor), skill_name
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in (
"用户已明确说“记住 / 更新 / 退役”",
"同轮按 `cs-keep` 处理",
"不重复确认",
):
assert _contains_contract(body, anchor), skill_name
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
for anchor in (
"Epic 子项不展示、不询问",
"每个子项至多把一条去重候选写入既有游标证据区",
"最终毕业清单一次处理",
"复用最终 owner gate",
"不得询问“是否继续下一项”",
"不得把普通子项完成当作终态返回",
):
assert _contains_contract(epic, anchor)
def test_task_skills_allow_only_two_narrow_lesson_maintenance_paths() -> None:
signatures = {}
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
signatures[skill_name] = {
anchor
for anchor in NARROW_LESSON_MAINTENANCE_CONTRACT
if _contains_contract(body, anchor)
}
assert _contains_contract(body, "创建、改写规则/scope、晋升、删除与跨项目反馈仍须")
assert _contains_contract(body, "随当次代码、证据和游标进入同一语义原子 milestone")
assert len({frozenset(signature) for signature in signatures.values()}) == 1
for skill_name, signature in signatures.items():
assert signature == NARROW_LESSON_MAINTENANCE_CONTRACT, skill_name
def test_keep_never_writes_v1_compound() -> None:
_, keep = _read_skill(SKILLS / "cs-keep/SKILL.md")
assert "`.codestable/compound/` 是只读历史知识源" in keep
assert "有增量时" in keep
assert "`.codestable/lessons/`" in keep
assert "能合并就更新旧文件" not in keep
def test_keep_owns_the_three_state_lesson_lifecycle() -> None:
frontmatter, keep = _read_skill(SKILLS / "cs-keep/SKILL.md")
assert str(frontmatter["description"]).startswith(
"管理有证据的项目事实、lesson 生命周期与 canonical 归宿"
)
for anchor in (
"status: observed",
"scope: 模块 / 命令 / 场景关键词",
"适用 / 不适用:边界与停止应用信号",
"证据最多三个代表性路径、测试、diff 或任务指针",
"候选归宿test | checker | attention | project-doc | adr | codestable-eval",
"`observed`",
"尚未在独立后续任务验证",
"`validated`",
"非创建该 lesson 的任务和 agent invocation 中有效命中",
"真实改善行为并验证成功",
"明确排除一个具体且合理的错误路径",
"必须记录 lesson 实际改变的计划或验证",
"本次通过的验收证据",
"`retired`",
"不得应用且不再复活原结论",
"旧 lesson 缺 `status` 按 `observed` 读取",
"不批量迁移",
"不得保存原始对话、逐次命中日志或无限 evidence history",
"Epic 最终毕业 gate 批准候选",
):
assert _contains_contract(keep, anchor)
def test_keep_promotes_or_retires_without_creating_parallel_truth() -> None:
_, keep = _read_skill(SKILLS / "cs-keep/SKILL.md")
for anchor in (
"机械 guard 优先",
"测试、checker、lint、类型或 deterministic helper",
"高频必读事实进入 `attention.md`",
"全文保持 ≤25 条",
"难回退、缺少上下文会令人意外、源于真实取舍",
"其他稳定方法进入项目既有文档",
"目标不存在时请 owner 选择",
"不发明目录",
"先验证新 owner",
"同一更新中删除重复 lesson",
"约 50 条预算",
"`codestable-eval` 只标记未来上游候选",
"不导出、不上传、不改 skill",
):
assert _contains_contract(keep, anchor)
for anchor in (
"新建、改写规则/scope、晋升、删除或跨项目分享仍需用户显式授权",
"不能把创建该 lesson 的同一任务自证为 validated",
"retired 条目上的新结论必须另建 observed lesson",
"不因命中次数或模型自评晋级",
):
assert _contains_contract(keep, anchor)
def test_onboard_keeps_the_base_skeleton_minimal() -> None:
_, onboard = _read_skill(SKILLS / "cs-onboard/SKILL.md")
skeleton = onboard.split("```text", 1)[1].split("```", 1)[0]
assert "epics/" not in skeleton
assert "requirements/" not in skeleton
assert "首次 Epic" in onboard
assert "`.codestable/epics/` 不属于基础骨架" in onboard
assert "按需创建" in onboard
for path in LEGACY_KNOWLEDGE_DIRS:
assert f"`{path}`" in onboard
def test_requirements_only_follow_an_explicit_canonical_owner() -> None:
for skill_name in ("cs-feat", "cs-epic"):
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
assert "`.codestable/attention.md` 明确记录" in body, skill_name
assert "canonical requirement" in body, skill_name
assert "不存在时不新建 `.codestable/requirements/`" in body, skill_name
def test_review_delegation_discovers_subagent_management_then_selects() -> None:
for skill_name in ("cs-feat", "cs-issue", "cs-refactor", "cs-epic"):
_, caller = _read_skill(SKILLS / skill_name / "SKILL.md")
assert "当前主流程创建 reviewer 前" in caller, skill_name
assert "当前会话可调用的 subagent 创建与管理能力" in caller, skill_name
assert "项目上下文有显式创建方式/model 约束时先遵守" in caller, skill_name
assert "达到审查质量基线后" in caller, skill_name
assert "优先选择与实现者异构的 agent" in caller, skill_name
assert "受管理的结构化委派能力" in caller, skill_name
assert "宿主 subagent" in caller, skill_name
assert "本机有界 agent CLI 回退" in caller, skill_name
assert "不得只扫 PATH" in caller, skill_name
assert "显式指定最强稳定 `model`" in caller, skill_name
assert "禁止依赖默认模型" in caller, skill_name
assert "最终创建方式、agent/model 与回退原因写入 task packet" in caller, skill_name
assert "通道" not in caller, skill_name
anchors = (
"当前主流程创建 reviewer 前",
"当前会话可调用的 subagent 创建与管理能力",
"项目上下文有显式创建方式/model 约束时先遵守",
"达到审查质量基线后",
"优先选择与实现者异构的 agent",
"受管理的结构化委派能力",
"宿主 subagent",
"本机有界 agent CLI 回退",
"最终创建方式、agent/model 与回退原因写入 task packet",
)
positions = [caller.index(anchor) for anchor in anchors]
assert positions == sorted(positions), skill_name
def test_review_delegation_keeps_a_healthy_run_bound() -> None:
for skill_name in ("cs-feat", "cs-issue", "cs-refactor", "cs-epic"):
_, caller = _read_skill(SKILLS / skill_name / "SKILL.md")
assert "reviewer 创建后绑定该运行" in caller, skill_name
assert "状态健康时等待终态报告" in caller, skill_name
assert "`Awaiting` 携带可查询的同一 run identity" in caller, skill_name
assert "后来发现更优创建方式" in caller, skill_name
assert "取消、重复创建或并行补发" in caller, skill_name
assert "能力不满足或目标失效" in caller, skill_name
def test_review_reuses_one_reviewer_lineage_for_finding_driven_repairs() -> None:
lineage_contract = (
"每个独立审查阶段的首轮必须由当前主流程创建一个 fresh reviewer",
"一个独立审查阶段由单一审查目的界定",
"design review、change review、contract review 与 Epic final acceptance 是不同阶段",
"只有为本阶段 findings 所作修复的复审",
"先修复并重跑验证,再冻结新的完整审查目标",
"同一 reviewer 的同一 session",
"完整当前候选与本轮修复增量",
"`resolved` / `unresolved` / `new findings`",
"不得只核对旧 finding 或机械打勾",
"累计最多 3 个有终态报告的轮次",
"更换 reviewer 不重置计数",
"只有原 run/session 失败或不可恢复、能力不满足、目标、范围、设计或核心路径发生重大变化",
"reviewer 声明无法继续独立判断",
"owner 要求第二意见",
"独立于实现者,不要求对自身上一轮审查失忆",
)
for skill_name in ("cs-feat", "cs-issue", "cs-refactor", "cs-epic"):
_, caller = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in lineage_contract:
assert _contains_contract(caller, anchor), f"{skill_name}: missing {anchor!r}"
assert "处理后重跑验证、重新冻结审查目标并创建 fresh reviewer" not in caller
assert "需要复审时重新创建 reviewer" not in caller
assert "按需重新创建 reviewer" not in caller
assert "需要时重新创建 reviewer" not in caller
assert "按需重新发起" not in caller
trigger_contract = {
"cs-epic": "交确认前进入 design review 审查阶段",
}
for skill_name, anchor in trigger_contract.items():
_, caller = _read_skill(SKILLS / skill_name / "SKILL.md")
assert _contains_contract(caller, anchor), skill_name
_, review = _read_skill(SKILLS / "cs-review/SKILL.md")
for anchor in (
"首轮 task packet 传入单一审查目的",
"design review、change review、contract review 与 Epic final acceptance 使用不同阶段",
"同一 reviewer 的同一 session",
"完整当前候选与本轮修复增量",
"`resolved` / `unresolved` / `new findings`",
"独立于实现者,不要求对自身上一轮审查失忆",
):
assert anchor in review
assert "不修复、不自行发起复审" in review
assert "可承接来源流程发给同一 session 的 follow-up" in review
assert "目标变化则本轮失效,由调用方重新冻结后创建 fresh reviewer" not in review
assert "在进入本 skill 前完成 reviewer 创建方式与 agent/model 选择并创建 fresh reviewer" not in review
def test_ordinary_task_skills_publish_minimum_sufficient_assurance() -> None:
for skill_name in ORDINARY_TASK_SKILLS:
_, skill = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in MINIMUM_SUFFICIENT_ASSURANCE_CONTRACT:
assert _contains_contract(skill, anchor), (
f"{skill_name}: missing minimum-assurance contract {anchor!r}"
)
def test_ordinary_change_review_is_risk_triggered_not_default() -> None:
forbidden_shortcuts = (
"默认进入 change review",
"仅文案级微小改动",
"仅单行级微小修复",
"仅微小整理",
)
review_contract = (
"独立 change review 不再默认发生",
"权限、安全、隐私或其他信任边界",
"持久化数据、schema 或迁移路径",
"并发、顺序或一致性语义",
"不可恢复的代码外副作用",
"review 实际触发后才应用 `审查协议` 中的 reviewer 创建、目标冻结、lineage、findings 与轮次条款",
"以下 reviewer 创建、目标冻结、lineage、findings 与轮次条款仅在 review 被触发后生效",
"commit / 里程碑授权门槛始终生效",
)
for skill_name in ORDINARY_TASK_SKILLS:
_, skill = _read_skill(SKILLS / skill_name / "SKILL.md")
for shortcut in forbidden_shortcuts:
assert shortcut not in skill, f"{skill_name}: keeps shortcut {shortcut!r}"
for anchor in review_contract:
assert _contains_contract(skill, anchor), (
f"{skill_name}: missing risk-triggered review contract {anchor!r}"
)
def test_ordinary_task_skills_add_only_corresponding_assurance() -> None:
risk_mapping = (
"目标、根因或实现方向仍不确定",
"破坏兼容性或改变多消费者依赖的公开契约",
"契约确认、对应契约测试与 canonical 文档",
"改变权限、安全、隐私或其他信任边界",
"改变持久化数据、schema 或迁移路径",
"兼容/迁移验证",
"改变并发、顺序或一致性语义",
"对应竞态/顺序验证",
"产生不可恢复的代码外副作用",
"dry-run、幂等、补偿或恢复证据",
"性能回退或性能敏感路径变化",
"定向 profile、基线或前后对比",
"改动影响面广或失败可跨模块传播",
"扩大到受影响回归",
"连续性需要不是风险门槛",
"只增加单一临时 work 游标",
"成本最低且足够权威的验证",
"已有定向测试足够时不叠加全量套件、浏览器 smoke 与独立 review",
)
for skill_name in ORDINARY_TASK_SKILLS:
_, skill = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in risk_mapping:
assert _contains_contract(skill, anchor), (
f"{skill_name}: missing assurance mapping {anchor!r}"
)
_, feat = _read_skill(SKILLS / "cs-feat/SKILL.md")
assert "出现任何一条,走设计对齐再动手" not in feat
assert "高风险任务的 work 文档在设计对齐时已建立" not in feat
_, refactor = _read_skill(SKILLS / "cs-refactor/SKILL.md")
assert "全部完成后跑完整验证" not in refactor
assert _contains_contract(
refactor,
"全部完成后必须运行覆盖受影响调用点和模块的回归",
)
assert _contains_contract(
refactor,
"只有全量套件按独立风险决定是否叠加",
)
assert _contains_contract(
refactor,
"全部改动完成后始终执行上述受影响回归",
)
assert "## 验证范围" in refactor
assert "## 审查协议" in refactor
def test_minimum_assurance_preserves_task_specific_safety_contracts() -> None:
_, issue = _read_skill(SKILLS / "cs-issue/SKILL.md")
for anchor in (
"根因超出已授权 scope",
"请 owner 决定",
"不得借修复擅自扩大改动",
):
assert _contains_contract(issue, anchor)
_, feat = _read_skill(SKILLS / "cs-feat/SKILL.md")
design_contract = (
"design 被触发时",
"改什么、契约变化或不变、真实取舍",
"必须修改 / 需要验证 / 仍待调查",
"packet 形式也必须包含这些内容",
)
for skill_name in ORDINARY_TASK_SKILLS:
_, skill = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in design_contract:
assert _contains_contract(skill, anchor), (skill_name, anchor)
def test_design_review_accepts_file_or_frozen_packet_text() -> None:
target_contract = (
"仓库内已有 design 文档版本",
"task packet 内原样全文 + SHA-256",
"reviewer 审查的目标就是该文本",
"最新全文、前后 hash 与修复摘要",
)
for skill_name in (*TASK_SKILLS, "cs-review"):
_, skill = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in target_contract:
assert _contains_contract(skill, anchor), (
f"{skill_name}: missing packet design target contract {anchor!r}"
)
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
assert "Epic design review 优先冻结永久文档版本" in epic
def test_cs_routes_owner_without_preselecting_assurance_strength() -> None:
_, cs = _read_skill(SKILLS / "cs/SKILL.md")
for anchor in (
"任务类型只决定工程方法,实际风险决定保障强度",
"只选择 owning skill不预选流程强度",
"直接调用 owning skill 时得到同一语义",
"按风险或 Epic 契约触发的可用保障",
):
assert _contains_contract(cs, anchor)
assert "设计与需求澄清是 cs-feat / cs-epic 的内置步骤" not in cs
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
assert "子项通过其 owning skill 选定的保障与验证后" in epic
assert "子项通过其 owning skill 的验证与审查后" not in epic
def test_epic_final_acceptance_starts_a_separate_fresh_reviewer_lineage() -> None:
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
assert "final acceptance 是独立审查阶段" in epic
assert "另建 fresh reviewer" in epic
assert "不得沿用子项、此前 design review 或 contract review 的 reviewer lineage" in epic
assert "主流程按同一 lineage 处理该阶段 findings" in epic
assert "契约变化形成新的 contract review 审查阶段" in epic
assert "永久文档已批准后的执行中" in epic
def test_shipped_skills_do_not_bind_review_backend_products() -> None:
forbidden = (
"cs-agent-mcp",
"cs_agent",
"paseo",
"claude",
"codex",
"anthropic",
"openai",
"gpt-",
)
paths = [path for path in sorted(SKILLS.rglob("*")) if path.is_file()]
assert paths
# Host registration filenames are packaging surfaces, not runtime backend selection.
allowed_product_named_paths = {Path("cs-review/agents/openai.yaml")}
product_named_paths = {
path.relative_to(SKILLS)
for path in paths
if any(name in path.relative_to(SKILLS).as_posix().lower() for name in forbidden)
}
assert product_named_paths == allowed_product_named_paths
for path in paths:
text = path.read_text(encoding="utf-8").lower()
for product_name in forbidden:
assert product_name not in text, f"{path}: bound to {product_name!r}"
def test_review_snapshots_and_milestone_commits_are_not_conflated() -> None:
_, review = _read_skill(SKILLS / "cs-review/SKILL.md")
assert "冻结一个明确的审查目标" in review
assert "审查目标标识" in review
assert "reviewer 返回前不得移动该目标" in review
assert "diff review 优先 staged diff" in review
assert "design review 冻结对应文档版本" in review
assert "audit 冻结 commit + 范围标识" in review
for skill_name in ("cs-feat", "cs-issue", "cs-refactor", "cs-epic"):
_, caller = _read_skill(SKILLS / skill_name / "SKILL.md")
assert "diff review 优先 staged diff" in caller, skill_name
assert "design review 冻结对应文档版本" in caller, skill_name
assert "audit 冻结 commit + 范围标识" in caller, skill_name
assert "目标标识写入 task packet" in caller, skill_name
assert "重新冻结完整审查目标" in caller, skill_name
assert "有 blocking 或未被用户明确接受的 important 时不提交当前候选" in caller, skill_name
assert "正式里程碑 commit" in caller, skill_name
assert "WIP/checkpoint commit" in caller, skill_name
assert "不代表 review 通过" in caller, skill_name
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
assert "同一时间只允许一个 `current_item`" in epic
assert "不把多个子项堆进同一 diff" in epic
assert "milestone_commit" in epic
def test_epic_continues_without_a_per_item_owner_gate() -> None:
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
for anchor in (
"串行约束,不是每个子项的人工 gate",
"永久文档顺序中第一个依赖已满足的未完成子项",
"在同一受托主流程中继续执行",
"不得询问“是否继续下一项”",
"不得把普通子项完成当作终态返回",
"拆解确认本身不等于版本控制授权",
"按已记录的逐项 checkpoint 策略暂停",
"需要 owner 明确接受的 important findings",
"子项 owning skill 自身的确认门槛",
"进入 executing 前不得保留 `pending` 或非法组合",
"恢复后沿用游标策略,不重新询问是否继续",
"旧游标缺字段或组合非法时暂停一次补记/修正",
"每个语义原子 commit 后按项目、宿主或 owner 已确定的 branch/remote 策略发布",
"在集成验证与 final acceptance review 通过后、请求 owner 最终接受前发布一次",
"agent 不执行远端发布",
"发布失败时写入 `blocked_by` 并暂停",
"Epic 内的已有 commit 授权只指 `milestone_commit: authorized`",
):
assert anchor in epic
for field in ("item_progression", "milestone_commit", "remote_publish"):
assert field in epic
assert "`milestone_commit: manual` 只能搭配 `item_progression: per-item`" in epic
assert "`milestone_commit: manual` 只能搭配 `remote_publish: manual`" in epic
assert "`remote_publish: each-milestone` 只能搭配 `milestone_commit: authorized`" in epic
assert "`authorized + per-item` 是合法的显式逐项暂停策略" in epic
assert "每次只推进一个已确认子项" not in epic
def test_epic_parallel_progression_is_policy_gated_with_single_writer() -> None:
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
reference = (
SKILLS / "cs-epic/references/parallel-execution.md"
).read_text(encoding="utf-8")
for anchor in (
"`item_progression: continuous | per-item | parallel`",
"`item_progression: parallel` 只能搭配 `milestone_commit: authorized`",
"唯一编排者与唯一游标 writer",
"`active_items`",
"references/parallel-execution.md",
"并行允许并发但不强制",
"退化为串行推进,不改变游标策略字段",
"初始化 `active_items: []` 并保持 `current_item: null`",
"验证通过后才创建语义原子里程碑 commit",
):
assert anchor in epic, anchor
# 串行条款只约束串行策略,不得回到无条件串行。
assert "`continuous` 与 `per-item` 策略下,同一时间只允许一个 `current_item`" in epic
for anchor in (
"并行不新增 owner gate",
"只有主流程一个唯一 writer",
"worker 只在自己的隔离工作区内改动",
"集成按完成顺序串行",
"不把多个子项堆进同一 diff",
"正式里程碑 commit 只由主流程创建",
"reviewer 是叶子执行器,不得再创建子 agent",
"worker 不得派发其他执行 agent",
"worktree/branch 策略归宿主",
"`milestone_commit: authorized`",
"不得只扫 PATH",
"最强稳定 model",
"不为 worker 追求异构",
"禁止依赖默认模型",
"拿不准时不降档",
"dispatched -> delivered | blocked",
"delivered -> integrating | blocked",
"integrating -> integrated | blocked",
"只保留非终态项",
"验证通过前不推进主历史",
"不提前推进 HEAD、不引入 worker WIP 历史",
"验证通过后才创建唯一的语义原子里程碑 commit",
"恢复到集成前基线",
"`item-local`",
"`epic-global`",
"运行仍健康则继续绑定等待,不重复派发",
"只有确认旧 run 不可恢复且交付不可核实时,才重派 fresh worker",
):
assert anchor in reference, anchor
# 并行是调度层扩展:不得另造 owner gate、策略字段或第二个游标 writer。
assert "新增 owner gate" not in reference.replace("不新增 owner gate", "")
# 退化条件在主契约与协议中保持同一语义:全部合格能力不可用才退化。
for text in (epic, reference):
assert "全部合格 worker 创建能力或隔离能力均不可用" in text
# skill 是独立安装单元reference 不得引用不随包分发的仓库文档或具体后端。
assert "ADR-" not in reference
assert "docs/adr" not in reference
def test_epic_wayfinding_publishes_route_map_frontier_and_hitl_contract() -> None:
_, cs = _read_skill(SKILLS / "cs/SKILL.md")
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
wayfinding = (SKILLS / "cs-epic/references/wayfinding.md").read_text(
encoding="utf-8"
)
assert "大而路线仍不清晰时也只交给 `cs-epic`" in cs
for anchor in (
"路线尚不清晰时才读取 `references/wayfinding.md`",
"永久 Epic 文档就是唯一路线文档",
"proposed 阶段就是低分辨率文档内路线地图",
"路线清晰、可审查、可执行",
"route clear 不是新的 owner gate",
"批准后再把 `current_item` 设为第一个依赖已满足的子项",
"起草 proposed 永久 Epic 文档时,同时创建或复用对应 work 游标",
"先在项目已有明确的 Epic、RFC 或 initiative 归宿中按任务关键词扫描 `status: proposed` 的在途 Epic",
"存在 `.codestable/epics/` 时也按相同条件扫描其中候选",
"两类归宿并存时都纳入候选,项目已有归宿优先",
"仍不能唯一确定时列出候选并请 owner 选择",
"不自动合并、补游标或新建 Epic",
"清退 `待决策` 与 `尚未明确` 两节",
"route clear 前不得保留未解决的 HITL 节点",
"只把剩余 AFK 局部未知写入对应子项契约",
):
assert _contains_contract(epic, anchor), anchor
permanent = epic.split("永久文档最小结构", 1)[1].split(
"work 游标最小结构", 1
)[0]
assert "## 待决策" in permanent
assert "## 尚未明确" in permanent
assert "[AFK|HITL]" in permanent
assert "depends_on" in permanent
cursor = epic.split("work 游标最小结构", 1)[1].split(
"永久 `status`", 1
)[0]
assert "current_item: null" in cursor
assert "## 待决策" not in cursor
assert "## 尚未明确" not in cursor
assert "[AFK|HITL]" not in cursor
assert "depends_on" not in cursor
for anchor in (
"目的地先于路线",
"广度优先",
"frontier 只派生、不持久化",
"待决策",
"尚未明确",
"范围之外",
"仓库事实、外部资料以及能由已批准约束唯一推出的工程判断由 agent 自行解决",
"存在真实取舍的路线选择必须由 owner 决定",
"每个待决策节点必须标为 `AFK` 或 `HITL`",
"不得替 owner 回答 HITL 问题",
"不得把沉默当作选择",
"一次只向 owner 提交一个 HITL frontier 节点",
"route clear 前不得保留 `HITL` 节点",
"agent 不得单方判定 HITL 节点超出范围或失效",
"只有 `AFK` 的局部未知可以下放",
"涉及外部权限、代码外副作用或不可逆动作的 prerequisite 一律标为 `HITL`",
"仍须另获对应权限或确认",
"同一事项只能位于 `待决策`、`尚未明确`、`关键决策` 或 `非目标` 之一",
"重新计算 frontier",
"不把决策问题一对一变成 Epic 子项",
"不创建独立 issue、map 或第三套状态",
"不得把探索代码留在产品工作树或里程碑",
"探索产物不自动晋升为交付",
"未验证输入",
"不能再改变目标、范围、非目标、验收、子项边界、依赖或重大风险",
"完整 proposed Epic",
"现有 design review",
):
assert _contains_contract(wayfinding, anchor), anchor
def test_epic_separates_durable_record_from_execution_cursor() -> None:
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
assert "项目已有明确 Epic、RFC 或 initiative 归宿时沿用" in epic
assert "`.codestable/epics/{slug}.md`" in epic
assert "永久 Epic 文档" in epic
assert "`.codestable/work/epic-{slug}.md`" in epic
assert "执行游标" in epic
permanent = epic.split("永久文档最小结构", 1)[1].split(
"work 游标最小结构", 1
)[0]
for field in (
"起点",
"目标",
"范围",
"非目标",
"验收标准",
"子项契约",
"关键决策",
"最终交付索引",
"整体验收",
"遗留风险",
):
assert field in permanent
cursor_owner = epic.split("- **执行游标**", 1)[1].split(
"永久文档最小结构", 1
)[0]
for field in (
"永久文档指针",
"approved_revision",
"phase",
"当前子项",
"下一步",
"blocked_by",
"item_progression",
"milestone_commit",
"remote_publish",
"临时决策",
"证据",
"commit 指针",
):
assert field in cursor_owner
assert "不得复制目标、验收、子项定义或最终结论" in epic
assert "shasum -a 256 <epic-file>" in epic
assert "确认前保持 `pending`" in epic
assert "active 期间永久文档冻结" in epic
assert "终态 `accepted` / `superseded` / `cancelled`" in epic
assert "永久 Epic 文档不得删除" in epic
def test_epic_internalizes_goal_semantics_without_v1_runtime() -> None:
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
assert "拆解方案必须经用户确认" in epic
assert "目标、边界、验收、子项契约" in epic
assert "重新 review 并征得同意" in epic
assert "最新 owner 已批准的验收标准" in epic
assert "audit/acceptance review" in epic
assert "owner 最终接受" in epic
assert "不恢复 `cs-goal` 入口" in epic
assert "`state.yaml`" in epic
assert "逐轮 iteration 报告" in epic
assert not (SKILLS / "cs-goal").exists()
assert not any(
path.name in {"state.yaml", "goal-state.yaml", "goal-plan.md"}
for path in (SKILLS / "cs-epic").rglob("*")
)
assert not any(
"iterations" in path.parts for path in (SKILLS / "cs-epic").rglob("*")
)
def test_build_cs_skill_requires_semantic_and_host_safe_validation() -> None:
build_root = LOCAL_SKILLS / "build-cs-skill"
build = (build_root / "SKILL.md").read_text(encoding="utf-8")
openai = yaml.safe_load(
(build_root / "agents/openai.yaml").read_text(encoding="utf-8")
)
spec = (build_root / "references/cs-skill-spec-standard.md").read_text(
encoding="utf-8"
)
gates = (build_root / "references/cs-skill-quality-gates.md").read_text(
encoding="utf-8"
)
for path in build_root.rglob("*.md"):
assert len(path.read_text(encoding="utf-8").splitlines()) <= 300, path
assert "$build-cs-skill" in openai["interface"]["default_prompt"]
assert "thin harness" in build
assert "thick context" in build
assert "data SkillShape" in build
assert "ThinOperator" in build
assert "ContextualWorkflow" in build
assert "ToolBackedWorkflow" in build
assert "data RulePlacement" in build
assert "placeRule :: Rule -> RulePlacement" in build
assert "not (independentSkillNeeded kind source) = NoActiveSkill" in build
assert "CompatibilityShim -> ShimSkill" in build
assert "ContextPlan" in build
assert "buildContextPlan" in build
assert "discover subagent creation and management capabilities callable in the current session" in build
assert "Reviewer creation methods prefer" in build
assert "Do not substitute a `PATH` executable scan for capability discovery" in build
assert "A healthy running delegation stays bound" in build
assert "idle without a return payload and no recoverable run identity" in " ".join(
build.split()
)
assert "subagent 创建与管理能力契约" in spec
assert "健康运行的 delegation" in gates
assert "无可恢复 run identity" in gates
assert "能力不匹配" in gates
assert "target 失效" in gates
assert "Haskell Contract Gate" in build
assert "CompatibilityShim -> ShimRoute" in build
assert "lifecycleDriven source -> LifecycleProtocol" in build
assert "algorithmic source -> AlgorithmProtocol" in build
placement = build[build.index("placeRule r"):build.index("buildContextPlan ::")]
placement_guards = (
"mechanizable r",
"nonMechanizableSafety r",
"projectSpecific r",
"stageSpecific r",
"everyInvocationNeeds r",
"otherwise",
)
positions = [placement.index(guard) for guard in placement_guards]
assert positions == sorted(positions)
assert "data RulePlacement" in spec
assert "NoActiveSkill" in spec
assert "ShimSkill" in spec
assert "ReferenceSkill" in spec
assert "placeRule :: Rule ->" not in spec
assert "Responsibility Contract" in spec
assert "Context Contract" in spec
assert "Collaboration Contract" in spec
assert "contractDecision :: Input -> State -> Outcome" in spec
assert "contractDecision _ _ = Blocked InvalidTransition" in spec
assert "`HumanCheckpoint` only for an actual owner decision" in spec
assert "`Awaiting` for already-started external work" in spec
assert "Every `HumanCheckpoint` must have an explicit resume input" in spec
assert "cross-skill handoff must retain its target and complete context" in spec
assert "## Haskell Contract Semantics Gate" in gates
assert "## Thin Harness Gate" in gates
assert "## Context Plan Gate" in gates
assert "## Evolution Compression Gate" in gates
assert "## Regression Ladder" in gates
assert "## Live Host Safety Gate" in gates
assert "## Family Audit Coverage Gate" in gates
assert "compare it with the reviewed/classified set by equality" in gates
assert "target the canonical main entry without selecting its internal stage/lane" in gates
assert "process start identity" in gates
assert "CI or a quiet disposable host" in gates
fixtures = (build_root / "references/cs-skill-fixture-patterns.md").read_text(
encoding="utf-8"
)
normalized_build = " ".join(build.split())
assert "data DelegationRole = Orchestrator | LeafExecutor" in build
assert "A `LeafExecutor` must not dispatch another agent" in build
assert "idle without a return payload" in normalized_build
assert "The calling orchestrator owns integration" in normalized_build
assert "outermost orchestrator" not in build
assert "`LeafExecutor`" in spec
assert "不得创建、委派、唤醒或跟进子 agent" in spec
assert "调用该 `LeafExecutor` 的 `Orchestrator`" in spec
assert "最外层 `Orchestrator`" not in spec
assert "idle/silence without return payload" in gates
assert "calling `Orchestrator`" in gates
assert "最外层 agent" not in gates
assert "review-leaf-does-not-delegate" in fixtures
assert "spawn_subagent" in fixtures
assert "wake_subagent" in fixtures
assert "follow_up_child" in fixtures
assert "invoke_cs_code_review" in fixtures
assert "return_idle_without_report" in fixtures
assert "review-prefers-managed-subagent-creation" in fixtures
assert "review-cli-is-bounded-fallback" in fixtures
assert "healthy-review-run-stays-bound" in fixtures
assert fixtures.count("step: selectReviewCreationMethod") >= 2
assert fixtures.count("step: monitorReviewRun") >= 2
assert "path_only_discovery" in fixtures
assert "selected_creation_method" in fixtures
assert "selected_channel" not in fixtures
assert "cancel_reviewer" in fixtures
assert "spawn_duplicate_reviewer" in fixtures
assert "当前 v2 活动 skill 不因历史 goal driver" not in fixtures
assert "read `.codestable/attention.md` just to author" not in build