mirror of
https://github.com/agent-substrate/substrate.git
synced 2026-10-02 03:24:42 +08:00
Follow up on the comment - https://github.com/agent-substrate/substrate/pull/1675#discussion_r4031619230 Stamps `actor_template_uid` onto `ExternalSnapshot` so template provenance travels with the snapshot itself, rather than being inferred from the single `ActorStatus.current_actor_template_uid`. #### Motivation `current_actor_template_uid` records the template the **last sprint booted with** (`finalizeRunning` stamps it on every resume). It does *not* record the template the **snapshot** was captured under. Those two diverge as soon as an actor runs a sprint that does not produce a new durable snapshot, and `loadActorForResume` was using the former to decide whether to force a `DATA`-only restore instead of `FULL`. Walking an actor through a repoint and a crash: | Step | Action | `current_…_uid` | `ExternalSnapshot` | |---|---|---|---| | **a** | Suspend on template **A** | A | captured on **A** | | **b** | `UpdateActor` repoints the spec to **B** | A | captured on **A** | | **c** | Resume → `A != B`, restores `DATA`, sprint boots on **B** | **B** | still on **A** | | **d** | Actor crashes (or is reverted) — no new snapshot taken | B | still on **A** | | **e** | Resume → `current == target == B`, so **no repoint is detected** | B | still on **A** | At step **e** the old check reports "template not replaced" and restores the external snapshot in `FULL` — replaying a memory image captured under **A**'s sandbox on **B**. That is exactly the case the guard exists to prevent; it was silently defeated by the sprint at step **c** advancing `current_actor_template_uid` past the snapshot. *(Note: Paused actors do not face this divergence. Because `UpdateActor` is only allowed in the `SUSPENDED` state, a paused actor cannot have its template updated. Therefore, local checkpoints do not need separate template provenance tracking).* #### Changes - **Data Model Updates:** Added the `actor_template_uid` field to `ExternalSnapshot`. - **Snapshot Stamping:** Updated the capture logic to stamp external snapshots with the active sandbox's `ActorTemplate` UID when suspending an actor or creating an actor from a tag. - **Resume Evaluation Logic:** Modified the external resume logic to compare the target template UID against the specific snapshot's UID (`ExternalSnapshot.actor_template_uid`) rather than the actor's overall status. Local restores bypass this check entirely since templates cannot change during a pause. **Tests** - `TestResumeActor_AteletWireRequest` (unit): snapshot fixtures now carry `actor_template_uid`, since provenance is read from the snapshot rather than from actor status. - Functional expectations for create/update/resume/pause updated for the new field on the external snapshot golden files. - `TestUpdateTemplateLifecycle` (e2e): asserts `external_snapshot.actor_template_uid` after suspend and re-suspend. - **e2e (Update Template)**: Added coverage for repoint detection after a revert (verifying the `resume` → `revert` → `resume` path described in the table above). - **e2e (Combined Volumes)**: Added coverage to explicitly verify which volumes a revert rewinds. - [x] Tests pass - [x] Appropriate changes to documentation are included in the PR