@@ -1730,6 +1730,8 @@ func (n *Node) CloseTransaction() (NodesMutation, error) {
17301730 return NodesMutation {}, err
17311731 }
17321732
1733+ // time skippign should be called at the end of the transaction,
1734+ // so that all invalid tasks are deleted.
17331735 if err := n .closeTransactionHandleTimeSkipping (); err != nil {
17341736 return NodesMutation {}, err
17351737 }
@@ -2197,29 +2199,6 @@ func (n *Node) closeTransactionHandleTimeSkipping() error {
21972199 return nil
21982200}
21992201
2200- // validateSerializedTask deserializes a serialized component task on this node and runs its validator
2201- // against current component state, returning true only if the task is still valid. It mirrors the
2202- // per-task validation in closeTransactionCleanupInvalidTasks and is used by the time-skipping paths
2203- // (calculateTimeSkippingTransition, regenerateTasksForTimeSkipping) so that an invalidated task — e.g. a
2204- // timeout whose activity already executed — is neither chosen as a skip target nor re-stamped. The component
2205- // value is hydrated first (prepareComponentValue is idempotent).
2206- func (n * Node ) validateSerializedTask (
2207- ctx Context ,
2208- task * persistencespb.ChasmComponentAttributes_Task ,
2209- ) (bool , error ) {
2210- if err := n .prepareComponentValue (ctx ); err != nil {
2211- return false , err
2212- }
2213- taskInstance , err := n .deserializeComponentTask (task )
2214- if err != nil {
2215- return false , err
2216- }
2217- return n .validateTask (ctx , TaskAttributes {
2218- ScheduledTime : task .GetScheduledTime ().AsTime (),
2219- Destination : task .GetDestination (),
2220- }, taskInstance )
2221- }
2222-
22232202func (n * Node ) defaultFindNextTargetTime (transition * TimeSkippingTransition ) error {
22242203 now := transition .CurrentTime
22252204 for _ , node := range n .andAllChildren () {
@@ -2246,16 +2225,6 @@ func (n *Node) defaultFindNextTargetTime(transition *TimeSkippingTransition) err
22462225 return nil
22472226}
22482227
2249- // regenerateChasmTasksForTimeSkipping re-emits physical timer tasks after a time-skipping transition
2250- // so their wall-clock visibility reflects the new accumulated skip.
2251- //
2252- // "Regenerate all" by default: every CategoryTimer task (pure and side-effect) across the tree is
2253- // reset to physicalTaskStatusNone and re-generated. BOTH pure and side-effect tasks can be
2254- // future-scheduled (CategoryTimer) tasks that need re-stamping.Immediate Transfer/Outbound/Visibility
2255- // tasks are left untouched.
2256- //
2257- // Invalidated tasks are excluded: each task is validated (validateSerializedTask) before being reset or
2258- // re-stamped, so a task whose validator now rejects it is left alone rather than re-emitted.
22592228func (n * Node ) regenerateChasmTasksForTimeSkipping (ctx Context ) error {
22602229 archetypeID := n .ArchetypeID ()
22612230
@@ -2272,25 +2241,11 @@ func (n *Node) regenerateChasmTasksForTimeSkipping(ctx Context) error {
22722241 if taskCategory (sideEffectTask ) != tasks .CategoryTimer {
22732242 continue
22742243 }
2275- valid , err := node .validateSerializedTask (ctx , sideEffectTask )
2276- if err != nil {
2277- return err
2278- }
2279- if ! valid {
2280- continue
2281- }
22822244 sideEffectTask .PhysicalTaskStatus = physicalTaskStatusNone
22832245 node .closeTransactionGeneratePhysicalSideEffectTask (sideEffectTask , nodePath , archetypeID )
22842246 }
22852247
22862248 for _ , pureTask := range componentAttr .GetPureTasks () {
2287- valid , err := node .validateSerializedTask (ctx , pureTask )
2288- if err != nil {
2289- return err
2290- }
2291- if ! valid {
2292- continue
2293- }
22942249 pureTask .PhysicalTaskStatus = physicalTaskStatusNone
22952250 if firstPureTask == nil || comparePureTasks (pureTask , firstPureTask ) < 0 {
22962251 firstPureTask = pureTask
0 commit comments