fix(annotate): re-emit plan at every subtask boundary

Previously only emitted a plan at t=0 and on interjections, so the
active plan rendered into training carried "done" subtasks until
the next interjection. With the new "plan = remaining subtasks"
summariser this meant the plan was stale between boundaries.

Emit a fresh plan row at every subtask start. ``active_at(t)`` then
returns a plan that contains exactly the subtasks whose start ≥
the current span's start — completed subtasks fall off the plan
the moment the next subtask begins.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pepijn
2026-05-13 16:26:49 +02:00
parent dd97c33814
commit a8ca5128b8
@@ -116,18 +116,29 @@ class PlanSubtasksMemoryModule:
"tool_calls": None, "tool_calls": None,
} }
) )
# plan row at t=0 # Plan rows at every subtask boundary — including t=0 (start of
plan_text = self._generate_plan(record, subtask_spans, task=effective_task) # the first subtask). Because the plan is just a numbered list
if plan_text is not None: # of *still-todo* subtasks, re-emitting at each boundary makes
rows.append( # the active plan shrink as work progresses: at frame t the
{ # rendered ``${plan}`` is the most recent emission, which
"role": "assistant", # contains exactly the subtasks that started at or after the
"content": plan_text, # current span. Saves the runtime from having to derive
"style": "plan", # "what's still left" at inference time.
"timestamp": float(t0), for span in subtask_spans:
"tool_calls": None, boundary_t = _snap_to_frame(span["start"], record.frame_timestamps)
} plan_text = self._generate_plan(
record, subtask_spans, refresh_t=boundary_t, task=effective_task
) )
if plan_text is not None:
rows.append(
{
"role": "assistant",
"content": plan_text,
"style": "plan",
"timestamp": float(boundary_t),
"tool_calls": None,
}
)
# memory rows at every subtask boundary except the very first start # memory rows at every subtask boundary except the very first start
prior_memory = "" prior_memory = ""
for i, span in enumerate(subtask_spans[1:], start=1): for i, span in enumerate(subtask_spans[1:], start=1):