-
Гильмуллин Руслан Ниязович создал
* feat(adopt): worker + scenarioRunner adopt DebugSession (engine #102) Adopts the v7 alpha.6 engine API (run sync + callback-free; new DebugSession class for interactive debugging): - scenarioRunner: replaces `machine.run({onStep, onPause})` with a `new turing.DebugSession(machine, ...)` + `.on('step'/'pause')` + start(). - machineWorker: at the run() call site, constructs either a Turing DebugSession (for TuringMachine) or a PostDebugSession via pm.debugRun() (for PostMachine), wires the existing onPauseFn / onIterFn / onStep handlers via session.on(...), and drives via session.start(). Pause listeners call session.continue() after dispatchPause resolves. Caveat — iter-synthesized step pauses: DebugSession iter listeners fire fire-and-forget (Node EventEmitter semantics, established in engine #102 PR discussion). The existing onIterFn calls dispatchPause + awaits a worker-side resume; with fire-and-forget iter, that await no longer blocks the engine. The UX of "Step button = run one iter, then pause" may need a follow-up tweak (use session.pause() inside iter listener instead of dispatchPause) — left for the dedicated demo migration PR. Breakpoint-driven pauses (the main use case) work cleanly via the pause event listener. Builds via the local npm link to the v7-alpha.6 engine and the post-machine-js adopt branch — when those publish, the peer-dep pin in machines-demo's package.json widens to ^7.0.0-alpha.6. * fix(worker): return iter listener's Promise to the engine (engine #102) The iter listener was wrapped in 'void onIterFn(m)' — the listener returned undefined, so the engine's 'await fn(m)' awaited nothing. RUNNING_STEP and RUNNING_AUTO broke: onIterFn's internal awaits (synthetic dispatchPause, throttle setTimeout) ran in parallel with the engine, which advanced freely through all iters in one click. Drop the void and let the listener return the Promise. The engine's awaited dispatch then properly blocks on the demo's per-iter coordination — Step pauses after one iter, Run-with-pause throttles between iters. * fix(worker): halt breakpoint toggle uses boolean directly; drop ugly casts (#102) Two fixes: 1. **Halt breakpoint couldn't be unchecked.** `entry.state.debug` for haltState is a single boolean (turing-machine-js#207), not a DebugConfig. Reading `.before` / `.after` on a boolean returns undefined, so `current` was always `{before:false, after:false}` and `mergeDebugKinds` flipped the kind back ON every click. Branch out to the haltState path BEFORE the per-side bit read and toggle the boolean directly. 2. **Drop `m as unknown as OnPausePayload` double casts** on the pause / iter listener wiring. Root cause: the local `OnPausePayload` had a `nextState.debug` field whose shape didn't match the engine's `nextState` (a State with `DebugConfig | boolean` debug). That field was never actually read by the worker — purely vestigial. Cleanup: redefine `OnPausePayload` as `Omit<MachineYield, 'state'> & { state: MachineYield['state'] & { name?: string }; debugBreak?: ... }`. The result is structurally assignable FROM MachineYield, so engine yields flow into the local handlers as-is — no casts at the call sites. Verified: npm run check (0 errors), npm test (176 pass), npm run lint (clean), npm run test:e2e (8/8 cold-start scenarios pass). * adopt(demo): engine pause descriptor m.pause {side,cause} (engine #102) Follows the engine reshape (raw runStepByStep yields carry no pause field; DebugSession's `pause` event carries `m.pause: {side, cause}`, replacing `m.debugBreak: {before?, after?, cause}`): - machineWorker OnPausePayload: `debugBreak?` → `pause?: {side, cause}` (optional — iter events have no pause field). onPauseFn reads `m.pause?.side === 'after'` and translates pause.side into the worker→main {before?, after?} protocol (unchanged; MachineView reads it). - imminentHalt: gate reads `m.pause?.side === 'after'`. - scenarioRunner: emitPauseLine takes PausedMachineState; translates pause.side for formatPauseLine (the DebugSession migration was already in place). Verified against linked alpha.6 engine + post: check (0 errors), lint clean, 176 unit tests, and 8/8 Playwright cold-start e2e against a FRESH build (the prior e2e ran on a stale dist). * refactor(demo): rename worker→main `debugBreak` → `pause {side?, cause}` (engine #102) Completes the rename through the demo's internal worker↔ main protocol so it matches the engine's `m.pause` shape end-to-end (no more `debugBreak`). - types.ts `PausedResponse`: `debugBreak: {before?, after?}` → `pause: {side?: 'before'|'after'; cause: 'breakpoint'|'step'|'manual'}`. `side` is optional: worker-synthesized boundaries (Step button, click- pause) have no before/after timing. - worker: onPauseFn forwards the engine's `m.pause` as-is (no more before/after translation); the two synthetic dispatches now carry `{cause: 'step'}` (Step boundary) and `{cause: 'manual'}` (click-pause) instead of `{}` — the side-less shape still renders the generic "after applying command" line. - pauseLineFormat + MachineView: read `paused.pause.side`. - scenarioRunner: forwards `m.pause` straight into the PausedResponse. - machineRunner.test fixtures + e2e comment updated. check (0 errors), lint, 176 unit, 8/8 Playwright e2e on a fresh build. * docs(demo): worker protocol pause descriptor — debugBreak → pause {side?, cause} Aligns the live docs with the renamed worker↔ main `paused` payload: - README "Crosses the boundary" + CLAUDE.md worker-contract row now name the `pause: {side?, cause}` field. - graph-highlight-and-breakpoints §13a: after-fire detection reads `m.pause?.side === 'after'`. NOTE: docs/execution-model.md is intentionally NOT touched here — its sequence diagrams predate the DebugSession adoption (they still show `machine.run({onPause})` + the arm/restore Step mechanic), so a piecemeal debugBreak→pause edit would leave it incoherent. It needs a holistic refresh for the DebugSession worker, best done when finalizing the demo adoption PR. * chore(deps): bump engine + post to 7.0.0-alpha.6 * refactor(worker): drive Step/Pause through the engine DebugSession (engine #102) Stop hand-rolling pauses in onIter. The Step button now calls the engine's stepIn() and the Pause button its external pause(); every pause — breakpoint, step, manual — flows through the single engine `pause` event. The listener awaits main's resume decision and resumes via stepIn()/continue()/stop(). Consequences: - Step / click-Pause are now before-side (engine semantics), so the graph highlight + pause line show the about-to-fire transition. The consumers needed no change — `pauseBefore = pause.side === 'before'` routes them automatically. - onIter collapses to just the RUNNING_AUTO throttle (skipped while stepping). - Removed stepRequested / pauseRequested / dispatchedAfterThisIter and the now-dead `decideOnIter` (+ its tests) — Step is before-side and never collides with an after-side breakpoint, so the dedup is unnecessary. - session hoisted to module scope so the `pause` request can reach it. - e2e + CLAUDE.md updated for the before-side wording. Verified: check, lint, 171 unit tests, 8 Playwright e2e. * chore(release): v1.0.0-alpha.176e0e13e5