feat(ship): clarify delivery stop semantics

This commit is contained in:
2026-10-14 11:49:50 +08:00
parent 125bfe0c23
commit 19aac17a0a
8 changed files with 133 additions and 21 deletions
+16 -8
View File
@@ -10,7 +10,13 @@ import sys
from pathlib import Path
from typing import Any
from ship_lib import ensure_stage_layout, load_yaml, record_stage_event, stage_for_step
from ship_lib import (
STOP_AT_STATE,
ensure_stage_layout,
load_yaml,
record_stage_event,
stage_for_step,
)
SPEC_PLACEHOLDERS = (
"<用户可见的目标",
@@ -26,12 +32,6 @@ TASK_PLACEHOLDERS = (
FAULT_PLACEHOLDER = "<没有故障时删除"
DONE_TASK = frozenset({"verified", "merged", "done"})
READY_DEP = frozenset({"verified", "merged", "done"})
STOP_AT_STATE = {
"verified": "verified",
"review_ready": "pr_opened",
"validation_ready": "deployed",
"released": "deployed",
}
DELIVERY_STEPS: tuple[tuple[str, str, str], ...] = (
("verified", "verify", "tester"),
("pr_opened", "open_pr", "delivery-loop"),
@@ -173,6 +173,11 @@ def _next_delivery(
nxt = DELIVERY_STEPS[start]
state, step, skill = nxt
summary = f"派 worker 把 delivery.state 推进到 {state},加载 {skill}"
if step == "verify":
summary = (
"派 tester worker 做开发阶段验证:执行单元测试、新增功能集成测试和静态检查;"
"不执行合并后的完整 tester 回归"
)
if step == "regress":
summary = (
"派 tester worker 做合并后的完整回归:先发现父仓库和子项目的所有 tester "
@@ -323,7 +328,10 @@ def _decide_short(
actor="manager",
step="ask_user",
status="ask_user",
summary="stopAt 未配置,主会话向用户确认 verified / review_ready / validation_ready / released",
summary=(
"stopAt 未配置,主会话向用户确认 develop_verified / review_ready / "
"release_ready / released / deployed"
),
)
if state == "change_ready" and _needs_hunt(spec_md) and not _has_change_commit(current):
last = _manager(current).get("lastStep")
+12
View File
@@ -48,6 +48,18 @@ DELIVERY_STATE = frozenset(
"deployed",
}
)
# User-facing stop points. The two legacy names remain accepted so existing
# ship records continue to resolve to the new phase meanings.
STOP_AT_STATE = {
"develop_verified": "verified",
"review_ready": "pr_opened",
"release_ready": "regression_passed",
"released": "published",
"deployed": "deployed",
"verified": "verified", # legacy alias for develop_verified
"validation_ready": "regression_passed", # legacy alias for release_ready
}
STOP_AT = frozenset(STOP_AT_STATE)
SOURCE_KIND = frozenset({"user", "hunt", "ack", "pr", "feishu"})
COMMIT_ROLE = frozenset({"baseline", "merged", "head"})
+12
View File
@@ -13,6 +13,7 @@ from ship_lib import (
DELIVERY_STATE,
KIND,
SHIP_STATUS,
STOP_AT,
SOURCE_KIND,
TASK_STATUS,
check_ship_id,
@@ -77,6 +78,17 @@ def validate_ship_dir(ship_dir: Path) -> list[str]:
if not isinstance(data.get("title"), str) or not str(data.get("title")).strip():
_issue(issues, "title 不能为空")
for path, value in (
("stopAt", data.get("stopAt")),
("delivery.stopAt", (data.get("delivery") or {}).get("stopAt")
if isinstance(data.get("delivery"), dict) else None),
):
if value not in (None, "") and value not in STOP_AT:
_issue(
issues,
f"{path} 无效: {value!r}({', '.join(sorted(STOP_AT))})",
)
source = data.get("source")
if source is not None:
src = _mapping(source, "source", issues)