feat: software-engineering skill v0.5 (G7/G8 ops + iteration)

Stacked on v0.3 + v0.4 (HEAD d6522ba feat-full-auto): v0.3/v0.4
content preserved, not reverted. Adds G7 post-release ops and
observation (monitoring, errors, cost/quota, feedback, hotfix loop,
rollback triggers, ops manual) and G8 iteration and scaling (v1.1
handover list, contract v1->v2 protocol, new-end onboarding,
scale/performance, deprecation), with G6->G7 and G7->G8 gates,
DAG, gate table, coordinator derivation, G0-G8 todos, checklist,
09-ops and 10-iteration role templates, and ops-manual / v1.1
handover templates in both body and appendix. Settles web+React+
multi-viewport focus, cross-viewport E2E, web single-end release
with iOS/Android native postposed, open-source-first, and the
TypeScript full-stack default (user-request-only language change;
codex-app-server itself stays Python). Pending #199 and #205
merge, then one rebase round. PR only, do not merge or deploy.
This commit is contained in:
host committed 2026-11-03 02:48:54 +00:00
1 parent a605ff2f92
commit 44616a03dc
2 files changed
+489 -74

No files matched your search

@@ -0,0 +1,82 @@
"""software-engineering 技能 v0.5:G7/G8 关键词断言(轻量)。
只断言正文与附录都含有 v0.5 的关键概念,不逐字背诵全文:
版本号与上一版、G7 运维与 G8 迭代、运维手册与 v1.1 交接清单、
热修复与回滚触发、跨视口 E2E、开源优先与许可证口径、
TypeScript 默认栈与用户特别要求例外、iOS/Android 后置。
正文改了附录没同步时,附录部分就会失败。
门禁衔接断言单独检查:G6→G7 与 G7→G8 的条件词必须同时
出现在正文门禁表附近与附录协调员章节。
角色断言检查附录含 09-ops 与 10-iteration 章节标题。
"""
import unittest
from pathlib import Path
SKILL = Path(__file__).resolve().parents[1] / "skills" / "software-engineering" / "SKILL.md"
# 正文与附录都要有的关键词(词形与技能正文一致)
BOTH = ("v0.5", "G7", "G8", "运维手册", "v1.1 交接清单",
"热修复", "回滚触发", "跨视口", "开源优先", "MIT/Apache",
"SSPL", "TypeScript", "Fastify", "Drizzle 或 Prisma",
"Vitest", "用户特别要求", "iOS/Android 后置")
# 门禁衔接:正文与附录协调员章都要出现
GATES = ("G6→G7", "G7→G8")
class SoftwareEngineeringG7G8TestCase(unittest.TestCase):
def test_g7g8_in_body_and_appendix(self):
text = SKILL.read_text(encoding="utf-8")
main, sep, appendix = text.partition("## 附录:角色模板")
self.assertTrue(sep, "appendix marker missing")
self.assertIn("v0.4", main, "header must name the previous version")
self.assertIn("全自动模式", main, "header must keep v0.4 full-auto content")
self.assertIn("v0.3", main, "header must keep v0.3 content")
for kw in BOTH:
self.assertIn(kw, main, kw)
self.assertIn(kw, appendix, "appendix: " + kw)
def test_gate_transitions_in_body_and_coordinator(self):
text = SKILL.read_text(encoding="utf-8")
main, sep, appendix = text.partition("## 附录:角色模板")
self.assertTrue(sep, "appendix marker missing")
# 附录协调员章:从 00-coordinator 到下一个附录角色标题之间
coord_start = appendix.index("00-coordinator")
coord_end = appendix.index("## 附录角色:01-", coord_start)
coordinator = appendix[coord_start:coord_end]
for kw in GATES:
self.assertIn(kw, main, kw)
self.assertIn(kw, coordinator, "coordinator appendix: " + kw)
# 门禁条件词:G6→G7 侧与 G7→G8 侧的关键条件
self.assertIn("用户验收已确认", main)
self.assertIn("用户验收已确认", coordinator)
self.assertIn("运维观察期结论已写", main)
self.assertIn("运维观察期结论已写", coordinator)
self.assertIn("回滚触发是否命中", main)
self.assertIn("回滚触发是否命中", coordinator)
def test_g7g8_roles_in_appendix(self):
text = SKILL.read_text(encoding="utf-8")
_, sep, appendix = text.partition("## 附录:角色模板")
self.assertTrue(sep, "appendix marker missing")
self.assertIn("## 附录角色:09-ops", appendix)
self.assertIn("## 附录角色:10-iteration", appendix)
self.assertIn("下一轮 G0-G6", appendix)
self.assertIn("不是下一版已发布", appendix)
self.assertIn("不直接改契约", appendix)
def test_g7g8_templates_in_body_and_appendix(self):
text = SKILL.read_text(encoding="utf-8")
main, sep, appendix = text.partition("## 附录:角色模板")
self.assertTrue(sep, "appendix marker missing")
self.assertIn("运维手册模板", main)
self.assertIn("运维手册模板", appendix)
self.assertIn("v1.1 交接清单模板", main)
self.assertIn("v1.1 交接清单模板", appendix)
self.assertIn("未修缺陷", main)
self.assertIn("未修缺陷", appendix)
if __name__ == "__main__":
unittest.main()