收紧策划 continuation 游标防止旧 delivery 越权
新增 planning session latestDelegationId 直接后继校验,阻止旧 delivery 另起分支 保留用户修订周期内质量返工的 user_revision 语义并更新提交门注释 补充 continuation 边界回归与 Fast GDD 技术决策文档
This commit is contained in:
+65
-6
@@ -25,6 +25,25 @@ fn plan_coordinator_error(kind: &str, detail: impl AsRef<str>) -> String {
|
||||
format!("{kind}: {}", detail.as_ref())
|
||||
}
|
||||
|
||||
fn validate_plan_continuation_parent<'a>(
|
||||
latest_delegation_id: &str,
|
||||
delivery: &'a StaticDelegateDeliveryRecord,
|
||||
) -> Result<&'a str, String> {
|
||||
let original_id = delivery.repair_of_delegation_id.as_deref().ok_or_else(|| {
|
||||
plan_coordinator_error(
|
||||
"PLAN_ACTIVE_RUN_EXISTS",
|
||||
"已有 planning session 时不能创建第二条根 delegation",
|
||||
)
|
||||
})?;
|
||||
if latest_delegation_id != original_id {
|
||||
return Err(plan_coordinator_error(
|
||||
"PLAN_NEEDS_RECONCILIATION",
|
||||
"planning continuation 必须直接继承当前 session 的 latest delegation",
|
||||
));
|
||||
}
|
||||
Ok(original_id)
|
||||
}
|
||||
|
||||
fn plan_session_successor_base(previous: &PlanSessionV1) -> Result<PlanSessionV1, String> {
|
||||
let mut next = previous.clone();
|
||||
next.session_revision = previous.session_revision.checked_add(1).ok_or_else(|| {
|
||||
@@ -230,6 +249,45 @@ mod option_label_delimiter_tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod planning_continuation_parent_tests {
|
||||
use super::*;
|
||||
|
||||
fn delivery(repair_of_delegation_id: Option<&str>) -> StaticDelegateDeliveryRecord {
|
||||
new_static_delegate_delivery_with_contract(
|
||||
GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID,
|
||||
"supervisor-session",
|
||||
"supervisor-run",
|
||||
"delegate-action",
|
||||
"current-delivery",
|
||||
GAME_CREATOR_PROJECT_PLANNING_AGENT_ID,
|
||||
"planning-session",
|
||||
"planning-run",
|
||||
&[],
|
||||
&[],
|
||||
repair_of_delegation_id,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn continuation_must_extend_the_session_cursor() {
|
||||
let continuation = delivery(Some("older-delivery"));
|
||||
let error = validate_plan_continuation_parent("current-delivery", &continuation)
|
||||
.expect_err("older delivery must not become the current planning branch");
|
||||
assert!(error.contains("latest delegation"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn continuation_accepts_the_current_session_cursor() {
|
||||
let continuation = delivery(Some("current-delivery"));
|
||||
assert_eq!(
|
||||
validate_plan_continuation_parent("current-delivery", &continuation)
|
||||
.expect("current delivery is a valid continuation"),
|
||||
"current-delivery"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn plan_option_label_matches_answer(label: &str, normalized_answer: &str) -> bool {
|
||||
label == normalized_answer
|
||||
}
|
||||
@@ -584,12 +642,13 @@ pub(crate) fn ensure_plan_session_for_planning_child_task_at_locked(
|
||||
{
|
||||
return Ok(true);
|
||||
}
|
||||
let original_id = delivery.repair_of_delegation_id.as_deref().ok_or_else(|| {
|
||||
plan_coordinator_error(
|
||||
"PLAN_ACTIVE_RUN_EXISTS",
|
||||
"已有 planning session 时不能创建第二条根 delegation",
|
||||
)
|
||||
})?;
|
||||
// `latest_delegation_id` is the planning session's single continuation
|
||||
// cursor. A new child must extend that cursor directly; otherwise a
|
||||
// Supervisor can select an older claimed delivery and make an unrelated
|
||||
// branch look like the current session. Keep this check here, after the
|
||||
// exact-task replay fast path above, so replaying an already projected
|
||||
// child remains idempotent.
|
||||
let original_id = validate_plan_continuation_parent(&previous.latest_delegation_id, &delivery)?;
|
||||
let deliveries = list_static_delegate_deliveries_at(root)?;
|
||||
if static_delegate_lineage_contains_unknown_contract_status(
|
||||
&deliveries,
|
||||
|
||||
@@ -1189,9 +1189,10 @@ fn validate_current_session_cas(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// `user_revision` 只证明审批意见,不证明澄清。首次 collecting、澄清续跑和提交前
|
||||
/// 质量返工的 session 都没有 revise/reject `lastDecisionRef`;合法续跑会把该引用
|
||||
/// 带到新的 collecting successor 上。replay 不走这里。
|
||||
/// `user_revision` 只证明审批意见,不证明澄清。首次 collecting、澄清续跑和没有待处理
|
||||
/// 用户修订的普通质量返工 session 都没有 revise/reject `lastDecisionRef`;用户修订周期
|
||||
/// 内的 continuation(包括其质量返工)会把该引用带到新的 collecting successor 上。
|
||||
/// continuation 的直接父边由 planning coordinator 校验,replay 不走这里。
|
||||
fn validate_user_revision_requires_approval_decision(
|
||||
session: &PlanSessionV1,
|
||||
input: &PlanSubmitGddInputV1,
|
||||
|
||||
Reference in New Issue
Block a user