Add breakpointSteps to the CSE snapshot protocol#55
Conversation
Adds breakpointSteps: number[] to CseSnapshotMessage — a run-level array of 0-based step indices where a breakpoint (e.g. Python's breakpoint()) sits on top of the control. CseMachinePlugin.sendSnapshots takes it as an optional second argument; CseMachineHostPlugin.receiveSnapshots now receives it as a second parameter. Lets host apps wire up breakpoint-navigation controls for CSE-machine evaluators, matching the stepper's existing redexNodeType contract. Paired with a py-slang change that detects breakpoint() in the CSE machine and populates this array (source-academy/py-slang issue #189). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 55bc989 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR 💥 An error occurred when fetching the changed packages and changesets in this PR |
There was a problem hiding this comment.
Code Review
This pull request introduces breakpointSteps to the CSE snapshot protocol, allowing host applications to wire breakpoint-navigation controls for CSE-machine-based evaluators. The changes update CseMachinePlugin.sendSnapshots and CseMachineHostPlugin.receiveSnapshots to support and propagate this new array of step indices. The feedback suggests making breakpointSteps optional in the CseSnapshotMessage interface to ensure backward compatibility, and defensively verifying that message.breakpointSteps is an array at runtime before passing it to receiveSnapshots.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Make CseSnapshotMessage.breakpointSteps optional for backward compatibility with runners that predate this field, and defensively check Array.isArray(message.breakpointSteps) in the web plugin before passing it to receiveSnapshots, since messages cross a conduit channel boundary and could come from an older or malformed runner. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Addressed both suggestions in 5c35f18: |
|
@coderabbitai, any review comments? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
gh pr view 55 --repo source-academy/plugins --json title,body,files,commits -q '.'
echo "---FILES---"
gh pr diff 55 --repo source-academy/pluginsLength of output: 14705 🏁 Script executed: #!/bin/bash
set -euo pipefail
sed -n '1,80p' src/web/cse-machine/src/index.tsLength of output: 2465 The changes look solid overall — I checked the current diff (commits 668a454 and 5c35f18) and confirm both previously flagged points are addressed correctly:
A couple of minor, non-blocking observations for your consideration:
Neither of these blocks the PR — the core protocol addition, optional-field backward compatibility, and defensive parsing are all in good shape, and the test coverage across [resolve] |
changesets/action execs the `version` input directly instead of through a
shell, splitting it on whitespace and running the first token with the
rest as literal argv. `yarn changeset version && yarn install` therefore
sent `&&`, `yarn`, `install` to the changeset CLI itself as extra
positional arguments, which it rejected ("Too many arguments passed to
changesets — we only accept the command name as an argument"). That
aborted the version step before it could write any changes, so the
resulting "no commits between main and changeset-release/main" made the
action fail to open a Version Packages PR (seen on the #55 merge).
Wrap the compound command in `bash -c "..."` so bash — not changesets/action
— parses the `&&`.
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…tSteps @sourceacademy/common-cse-machine ^0.2.0 -> ^0.3.0 and @sourceacademy/web-cse-machine ^2.0.0 -> ^3.0.0, now that source-academy/plugins#55 has published (bumping the same two packages, plus runner-cse-machine, to carry breakpointSteps over the CSE snapshot channel). Unblocks this PR: tsc --noEmit passes against the real published CseMachineHostPlugin.receiveSnapshots(snapshots, breakpointSteps) signature. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tSteps @sourceacademy/common-cse-machine ^0.2.0 -> ^0.3.0 and @sourceacademy/runner-cse-machine ^1.0.0 -> ^3.0.0, now that source-academy/plugins#55 has published (bumping the same two packages, plus web-cse-machine, to carry breakpointSteps over the CSE snapshot channel). Unblocks this PR: tsc --noEmit passes against the real published CseMachinePlugin.sendSnapshots(snapshots, breakpointSteps?) signature. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…channel (#4083) * feat(cseMachine): wire breakpoint step indices from the CSE snapshot channel CseMachineHostPlugin.receiveSnapshots now takes breakpointSteps as a second argument (paired with the @sourceacademy/web-cse-machine protocol change), and handleCseSnapshots dispatches WorkspaceActions.updateBreakpointSteps with it alongside the existing snapshot/stepsTotal updates. The double- chevron breakpoint-navigation buttons in SideContentCseMachine already read props.breakpointSteps and are rendered unconditionally for the conductor/Python flow — they just needed real data instead of an empty array. No new UI. Depends on a py-slang change that detects breakpoint() in the CSE machine (source-academy/py-slang issue #189). package.json/yarn.lock currently point @sourceacademy/common-cse-machine and @sourceacademy/web-cse-machine at a local yarn-link portal to /home/vakshay/plugins for development; swap for a real published semver range once that plugins PR merges. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore: revert local yarn-link dev scaffolding for cse-machine packages package.json/yarn.lock were pointing @sourceacademy/common-cse-machine and @sourceacademy/web-cse-machine at a local yarn-link portal (/home/vakshay/plugins) for development. That doesn't resolve for anyone else or CI, and web-cse-machine can't be pinned to the plugins branch via Yarn's git+workspace protocol either (it depends on the sibling common-cse-machine workspace via workspace:*, and Yarn's single-workspace git fetch doesn't build sibling workspaces first, so the prepack/rollup step can't find its dist). Reverting to the original published semver ranges so this PR's dependency diff is clean. This PR depends on source-academy/plugins#55 (adds breakpointSteps to the CSE snapshot protocol) merging and publishing to npm before it will typecheck/build — opening as a draft until then. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore: bump cse-machine deps to the published versions with breakpointSteps @sourceacademy/common-cse-machine ^0.2.0 -> ^0.3.0 and @sourceacademy/web-cse-machine ^2.0.0 -> ^3.0.0, now that source-academy/plugins#55 has published (bumping the same two packages, plus runner-cse-machine, to carry breakpointSteps over the CSE snapshot channel). Unblocks this PR: tsc --noEmit passes against the real published CseMachineHostPlugin.receiveSnapshots(snapshots, breakpointSteps) signature. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore: formattin --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: henz <henz@comp.nus.edu.sg>
…rker (#256) * feat(cse-machine): support breakpoint() as a breakpoint-navigation marker Registers breakpoint() as a no-op MISC builtin (chapters 1-4) and, in the CSE machine's step generator, detects a zero-arg call resolving (by identity, so aliases like `bp = breakpoint; bp()` are caught too) to that builtin, recording the step where it sits on top of the control into context.runtime.breakpointSteps. Threads that array out through collectSnapshots and PyCseEvaluator's sendSnapshots call so the host's breakpoint-navigation controls can consume it (paired with a protocol change in source-academy/plugins to carry it across the Conductor __cse channel). Mirrors PR #197's substitution-stepper support of the same feature (issue #189). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore: revert local yarn-link dev scaffolding for cse-machine packages package.json/yarn.lock were pointing @sourceacademy/common-cse-machine and @sourceacademy/runner-cse-machine at a local yarn-link portal (/home/vakshay/plugins) for development. That doesn't resolve for anyone else or CI, and runner-cse-machine can't be pinned to a plugins branch via Yarn's git+workspace protocol either — like web-cse-machine, it depends on the sibling common-cse-machine workspace via workspace:*, and Yarn's single-workspace git fetch doesn't build sibling workspaces first, so the prepack/rollup step can't find its dist. Reverting to the original published semver ranges so this PR's dependency diff is clean. This PR depends on source-academy/plugins#55 (adds breakpointSteps to the CSE snapshot protocol) publishing a new npm version before it will typecheck/build against real installs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore: bump cse-machine deps to the published versions with breakpointSteps @sourceacademy/common-cse-machine ^0.2.0 -> ^0.3.0 and @sourceacademy/runner-cse-machine ^1.0.0 -> ^3.0.0, now that source-academy/plugins#55 has published (bumping the same two packages, plus web-cse-machine, to carry breakpointSteps over the CSE snapshot channel). Unblocks this PR: tsc --noEmit passes against the real published CseMachinePlugin.sendSnapshots(snapshots, breakpointSteps?) signature. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(cse-machine): address Gemini review on #256 Also reset context.runtime.changepointSteps and .break in evaluateChunk, alongside breakpointSteps -- same per-run leaking-state class, since this.context persists across evaluateChunk calls but only breakpointSteps was being reset. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore: formattin * Fix yarn.lock entry ordering for CI's hardened-mode install check The root workspace's dependency block had @sourceacademy/conductor listed after @sourceacademy/runner-cse-machine instead of before it alphabetically -- yarn.lock wasn't re-normalized when common-cse-machine/runner-cse-machine were bumped. This alone was enough to fail `yarn install --frozen-lockfile` under Yarn's hardened mode (auto-enabled for fork PRs), which treats any lockfile diff, including pure reordering, as forbidden. Regenerated via a plain `yarn install`; no dependency versions changed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Martin Henz <henz@nus.edu.sg> Co-authored-by: henz <henz@comp.nus.edu.sg>
…channel (#4083) * feat(cseMachine): wire breakpoint step indices from the CSE snapshot channel CseMachineHostPlugin.receiveSnapshots now takes breakpointSteps as a second argument (paired with the @sourceacademy/web-cse-machine protocol change), and handleCseSnapshots dispatches WorkspaceActions.updateBreakpointSteps with it alongside the existing snapshot/stepsTotal updates. The double- chevron breakpoint-navigation buttons in SideContentCseMachine already read props.breakpointSteps and are rendered unconditionally for the conductor/Python flow — they just needed real data instead of an empty array. No new UI. Depends on a py-slang change that detects breakpoint() in the CSE machine (source-academy/py-slang issue #189). package.json/yarn.lock currently point @sourceacademy/common-cse-machine and @sourceacademy/web-cse-machine at a local yarn-link portal to /home/vakshay/plugins for development; swap for a real published semver range once that plugins PR merges. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore: revert local yarn-link dev scaffolding for cse-machine packages package.json/yarn.lock were pointing @sourceacademy/common-cse-machine and @sourceacademy/web-cse-machine at a local yarn-link portal (/home/vakshay/plugins) for development. That doesn't resolve for anyone else or CI, and web-cse-machine can't be pinned to the plugins branch via Yarn's git+workspace protocol either (it depends on the sibling common-cse-machine workspace via workspace:*, and Yarn's single-workspace git fetch doesn't build sibling workspaces first, so the prepack/rollup step can't find its dist). Reverting to the original published semver ranges so this PR's dependency diff is clean. This PR depends on source-academy/plugins#55 (adds breakpointSteps to the CSE snapshot protocol) merging and publishing to npm before it will typecheck/build — opening as a draft until then. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore: bump cse-machine deps to the published versions with breakpointSteps @sourceacademy/common-cse-machine ^0.2.0 -> ^0.3.0 and @sourceacademy/web-cse-machine ^2.0.0 -> ^3.0.0, now that source-academy/plugins#55 has published (bumping the same two packages, plus runner-cse-machine, to carry breakpointSteps over the CSE snapshot channel). Unblocks this PR: tsc --noEmit passes against the real published CseMachineHostPlugin.receiveSnapshots(snapshots, breakpointSteps) signature. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore: formattin --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: henz <henz@comp.nus.edu.sg>
Summary
breakpointSteps: number[]toCseSnapshotMessagein@sourceacademy/common-cse-machine: a run-level array of 0-based step indices where a breakpoint (e.g. Python'sbreakpoint(), JS'sdebugger;) sits on top of the control.CseMachinePlugin.sendSnapshots(runner) takes it as an optional second argument (defaults to[]) and forwards it in the message.CseMachineHostPlugin.receiveSnapshots(web) now receives it as a second parameter, passed through from the message (?? []if absent).Why
Mirrors the stepper protocol's existing
redexNodeTypemarker field, which host apps use to drive breakpoint-navigation (double-chevron) controls. The CSE machine protocol had no equivalent, so a CSE-machine-based evaluator (e.g. py-slang, for source-academy/py-slang#189) had no way to tell the host which steps to jump to. This is a companion change to a py-slang change that detectsbreakpoint()in the CSE machine and populates this array, and a frontend change that wires it into the existingupdateBreakpointStepsRedux action.Test plan
common.test.ts,runner.test.ts,web.test.ts) — 66 tests passingtsc --noEmitclean on all three packagesdist/and confirmed the new field/param is present in the emitted bundle