Skip to content

feat(tutorial): run policies and run groups for overlapping callback runs - #3510

Draft
Ethanlita wants to merge 1 commit into
goplus:issue-3403-tutorial-v2from
Ethanlita:issue-3417-run-policies
Draft

Ethanlita wants to merge 1 commit into
goplus:issue-3403-tutorial-v2from
Ethanlita:issue-3417-run-policies

Conversation

@Ethanlita

@Ethanlita Ethanlita commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #3442 for #3509. Draft until the design discussion in #3509 settles (concept and naming, how many forms, whether to ship for the first release).

Rebased onto the integration branch now that #3442 has merged, so the diff is this one commit. Its comments are written in English like the rest of the framework.

What this adds

Since #3442, every trigger starts a new run of each registered callback and runs may overlap while one of them waits on the learner or on generation. This PR lets the author say how runs of one callback, or of several callbacks, relate:

judging := newRunGroup(SkipWhileBusy)

Editor.Runtime.onLog log => {
    if log != "reached" { return }
    judging.enter()          // from here on this run holds the group
    ...
}

Editor.Runtime.onExit code => {
    judging.enter()
    ...
}
  • RunPolicy: CancelPrevious (the joining run cancels the run holding the group; a cancelled run ends at its next waiting point and the result it was waiting on is discarded), OneAtATime (the joining run yields and waits its turn), SkipWhileBusy (the joining run ends on the spot).
  • newRunGroup(policy) and enter(); a group may be shared by callbacks of different events.
  • Registration-time forms onExit OneAtATime, code => {...} and onExit judging, code => {...} as sugar for joining from the first statement. Review preference so far is to ship a single form; these overloads are the part most likely to be dropped.
  • The author never checks a result: skipping and cancellation end the run through a sentinel that runFrame absorbs silently.

Internally: yieldWhile is the only yield point and the only place cancellation takes effect, so a cancelled run never touches a pending result; group state lives behind a leaf lock; the invariants checker pins the shape. Tests cover each policy, the shared group, result discarding, and registration-order starts; the bundle build test compiles all three registration forms through the real classfile pipeline.

Not in scope

Actively cancelling a host call that is already pending (closing the dialog, aborting the generation) needs an executor-level cancellation protocol and host support; here a cancelled run only stops at its next waiting point.

🤖 Generated with Claude Code

… runs

Since goplus#3442, every trigger starts a new run of each registered callback
and runs may overlap while one of them waits on the learner or on
generation. That reproduces the stale-result race the review call
discussed, and the agreed answer was cancelling or aborting stale
processing rather than queueing. This lets the author say how runs of
one callback, or of several callbacks, relate:

  CancelPrevious  the joining run cancels the run holding the group;
                  a cancelled run ends at its next waiting point and
                  the result it was waiting on is discarded
  OneAtATime      the joining run yields and waits for its turn
  SkipWhileBusy   the joining run ends on the spot

newRunGroup plus enter() lets a run join after filtering its trigger and
lets callbacks of different events share one policy; a policy or a group
given at registration joins from the first statement, through the __N
overloads XGo groups. The author never checks a result: skipping and
cancellation end the run through a sentinel that runFrame absorbs
silently.

yieldWhile is the only yield point and the only place cancellation takes
effect, so a cancelled run never touches a pending result. Group state
lives behind a leaf lock. The invariants checker pins the shape, the
docs example and the debug seed course use a group, and the bundle build
test exercises all three registration forms.

The design is still under discussion in goplus#3509; this branch carries the
implementation for that follow-up.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview – builder 6eba292e Deployed Sep 17, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant