fix(company): route delete cascade through transition_work_item; centralize resume identity restore

- delete_work_item descendant cascade now goes through transition_work_item
  (audit reason, attempt-ledger settlement, phase hooks) instead of raw
  store phase writes plus manual task.status mutation; task-owned audit
  stamps and execution-lock release only happen when a cancellation
  actually occurred, removing a desync path (task=CANCELLED under
  work_item=APPROVED) in drift scenarios.
- transition_work_item gains blocked_reason/handoff_status passthrough so
  callers no longer need a second store write for the same transition.
- new build_company_resume_identity_restore helper in metadata_ownership
  replaces the ad-hoc delegation_seat_id/role/session literals in
  engine._restore_and_pin_company_resume_execution_identity, keeping seat
  identity writes inside the ownership contract module.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
LZH-YS1998
2026-07-26 22:14:24 +08:00
parent 26e45217e5
commit 322a5ec9b1
4 changed files with 67 additions and 29 deletions
@@ -102,6 +102,8 @@ async def transition_work_item(
metadata_updates: dict[str, Any] | None = None,
release_claim: bool = False,
attempt_outcome: str | None = None,
blocked_reason: str | None = None,
handoff_status: str | None = None,
) -> DelegationWorkItem | None:
"""Transition a work item to ``target_phase``.
@@ -124,6 +126,10 @@ async def transition_work_item(
metadata_updates: Extra metadata keys to merge onto the work item.
release_claim: When True, clears the current claim so the dispatcher
can re-acquire. Useful for cancel / timeout / forced-release paths.
blocked_reason: Optional ``blocked_reason`` column value, folded into
the same write as the phase change (pass ``""`` to clear).
handoff_status: Optional ``handoff_status`` column value, folded into
the same write as the phase change.
Returns:
The updated ``DelegationWorkItem``, or ``None`` when the store lacks
@@ -166,6 +172,10 @@ async def transition_work_item(
}
if summary is not None:
kwargs["summary"] = summary
if blocked_reason is not None:
kwargs["blocked_reason"] = blocked_reason
if handoff_status is not None:
kwargs["handoff_status"] = handoff_status
if release_claim:
# Fold claim release into the same write as the phase change: the
# legacy two-call sequence could commit the phase and then fail the