fix(ticket): separate retained responsibility from unfinished work

T-715: end assignment work identities atomically on done/close without deleting responsibility. Reopen never reactivates old authority. Schema 82 preserves legacy closed assignments, historical removal plans and Worker attribution; active work drives admission, auth/routing, retention and cleanup while independent lifecycle/attachment fences remain.

Validation: root cargo check; cargo test -p yoi-workspace-server (630 lib + 11 bin), -p merge-request (20), -p worker (947); worker-runtime restore/removal filters (2); Deno ticket responsibility/runtime UI contracts (12); cargo fmt --all -- --check; git diff --check HEAD.
This commit is contained in:
2026-10-08 15:35:16 +09:00
parent b0d8c7b786
commit b6de908e9f
16 changed files with 1799 additions and 122 deletions
@@ -875,7 +875,7 @@ impl WorkerOperation {
"Restore a stopped Backend/Runtime Worker session in the current Workspace. Supply expected_observation_token from WorkerList; a conflict requires refreshing and deliberate new intent. New requests default to the durable Tool call ID. For explicit recovery of an unknown/pending outcome, supply the reported request_id and the original token unchanged; never create a new intent or automatically retry."
}
Self::Remove => {
"Remove an eligible stopped, unassigned, non-internal Worker. Supply a bounded reason; Backend validation and retention are authoritative."
"Remove an eligible stopped, non-internal Worker with no unfinished Ticket work. Terminal Ticket responsibility is retained and does not require unassignment. Supply a bounded reason; Backend validation and retention are authoritative."
}
}
}
@@ -1149,7 +1149,7 @@ pub fn description(n: &str) -> Option<&'static str> {
"Record Orchestrator-owned integration for the explicitly addressed Merge Request without completing the Ticket or releasing its assignment.",
),
"CompleteTicket" => Some(
"Complete the Ticket only after reviewing its current item revision and exact linked Merge Request result set; this releases the current assignment atomically.",
"Complete the Ticket only after reviewing its current item revision and exact linked Merge Request result set; this ends unfinished work atomically while retaining responsibility and assignment history.",
),
"ReviewMergeRequest" => Some(
"Submit the injected Reviewer capability result for its captured exact source ref; source movement cancels it, while target-only movement does not.",
+16 -2
View File
@@ -1027,7 +1027,7 @@ mod tests {
}
#[test]
fn builtin_orchestrator_cleanup_policy_renders_with_common_includes() {
fn builtin_orchestrator_cleanup_retains_terminal_responsibility_and_blocks_unfinished_work() {
let rendered = PromptCatalog::builtins_only()
.unwrap()
.render_name("role.orchestrator", Value::UNDEFINED)
@@ -1040,7 +1040,21 @@ mod tests {
assert!(rendered.contains("call `WorkerStop`"));
assert!(rendered.contains("call `WorkerRemove`"));
assert!(rendered.contains("only then call `WorkdirDelete`"));
assert!(rendered.contains("`CurrentAssignment` means unassign and reread"));
assert!(rendered.contains("must have no unfinished Ticket work"));
assert!(rendered.contains("does not require unassignment before cleanup"));
assert!(rendered.contains("`UnfinishedWork` (`unfinished_work` on the wire)"));
assert!(rendered.contains("requires explicit work end or reassignment"));
assert!(rendered.contains("idle or stopped status does not end unfinished work"));
for stale_policy in [
"no current Ticket assignment",
"unassign it through the available orchestration authority",
"`CurrentAssignment`",
] {
assert!(
!rendered.contains(stale_policy),
"stale cleanup policy: {stale_policy}"
);
}
assert!(!rendered.contains("{% include"));
}
}