feat: lifecycle events carry triggered_by_assistant_turn_id back-reference (T114.1)
Phase 3.5 T83.4 surfaced un-rolled-back lifecycle transitions on regenerate; T114 wires up the actual rollback. Step 1 is the back- reference: every event_started / event_completed / event_cancelled emitted by post_turn (chat/web/turns.py) and regenerate (chat/services/regenerate.py) now carries ``triggered_by_assistant_turn_id`` in its payload, set to the id of the assistant_turn event that produced the transition. Schema decision (Option A from the plan): no migration. The field is a payload convention only — older event_log rows lack it and rollback will skip them with a debug log when T114.3 lands. Forward-only. The post_turn lifecycle block already runs AFTER the assistant_turn event is appended (step 8a vs step 7), so ``primary_assistant_event_id`` is in scope. Same for regenerate: the lifecycle classification (step 9a) runs after step 6's append. **No emission-order reorder was needed** in either flow. Updates ``test_turn_with_event_transition_appends_started_event`` to assert the new field is present in the emitted event_started payload and points at the assistant_turn id.
This commit is contained in:
@@ -738,6 +738,12 @@ async def regenerate_assistant_turn(
|
||||
payload={
|
||||
"event_id": transition.event_id,
|
||||
"started_at": chat.get("time"),
|
||||
# T114.1: back-reference to the assistant_turn
|
||||
# that triggered this transition (see turns.py
|
||||
# for rationale).
|
||||
"triggered_by_assistant_turn_id": (
|
||||
new_assistant_event_id
|
||||
),
|
||||
},
|
||||
)
|
||||
elif transition.new_status == "completed":
|
||||
@@ -747,6 +753,10 @@ async def regenerate_assistant_turn(
|
||||
payload={
|
||||
"event_id": transition.event_id,
|
||||
"completed_at": chat.get("time"),
|
||||
# T114.1: back-reference (see above).
|
||||
"triggered_by_assistant_turn_id": (
|
||||
new_assistant_event_id
|
||||
),
|
||||
},
|
||||
)
|
||||
promote_completed_event(
|
||||
@@ -762,6 +772,10 @@ async def regenerate_assistant_turn(
|
||||
payload={
|
||||
"event_id": transition.event_id,
|
||||
"completed_at": chat.get("time"),
|
||||
# T114.1: back-reference (see above).
|
||||
"triggered_by_assistant_turn_id": (
|
||||
new_assistant_event_id
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -812,6 +812,14 @@ async def post_turn(
|
||||
payload={
|
||||
"event_id": transition.event_id,
|
||||
"started_at": chat.get("time"),
|
||||
# T114.1: back-reference to the assistant_turn that
|
||||
# triggered this transition. Regenerate uses this
|
||||
# to roll back lifecycle transitions when the turn
|
||||
# is superseded. Forward-only — older events
|
||||
# without this field are skipped by rollback.
|
||||
"triggered_by_assistant_turn_id": (
|
||||
primary_assistant_event_id
|
||||
),
|
||||
},
|
||||
)
|
||||
elif transition.new_status == "completed":
|
||||
@@ -821,6 +829,10 @@ async def post_turn(
|
||||
payload={
|
||||
"event_id": transition.event_id,
|
||||
"completed_at": chat.get("time"),
|
||||
# T114.1: back-reference (see above).
|
||||
"triggered_by_assistant_turn_id": (
|
||||
primary_assistant_event_id
|
||||
),
|
||||
},
|
||||
)
|
||||
# Run promotion inline so the artifact-emitting events
|
||||
@@ -842,6 +854,10 @@ async def post_turn(
|
||||
payload={
|
||||
"event_id": transition.event_id,
|
||||
"completed_at": chat.get("time"),
|
||||
# T114.1: back-reference (see above).
|
||||
"triggered_by_assistant_turn_id": (
|
||||
primary_assistant_event_id
|
||||
),
|
||||
},
|
||||
)
|
||||
# Any other ``new_status`` value falls through silently —
|
||||
|
||||
Reference in New Issue
Block a user