Skip to content

refactor(dev): replace dynamic updates with immutable sessions - #87

Merged
xusd320 merged 4 commits into
mainfrom
xusd320/refactor-dev-supervisor
Aug 10, 2026
Merged

refactor(dev): replace dynamic updates with immutable sessions#87
xusd320 merged 4 commits into
mainfrom
xusd320/refactor-dev-supervisor

Conversation

@xusd320

@xusd320 xusd320 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace in-place EVJS dev framework updates with a long-lived supervisor and immutable dev sessions.
  • Prevent repeated manifest generation and restart-required loops after transient framework input failures.
  • Make Utoopack Session replacement safe across native cache locks and its process-global loader scheduler.

Changes

  • Add semantic revision preparation and fingerprinting so ordinary source edits stay on bundler HMR while framework-semantic changes replace the Session once.
  • Add explicit DevSupervisor and DevSession ownership for watchers, ports, plugins, APIs, output queues, locks, and bundler controllers.
  • Publish a validated in-memory generated IR image directly to canonical .ev after the old Session closes; remove full-tree dev candidate, previous, restore, and system snapshot flows.
  • Simplify the internal bundler dev contract and migrate the Webpack and Utoopack adapters to immutable controllers with abort-aware callbacks and idempotent close behavior.
  • Route Utoopack shutdown through its acknowledged graceful cleanup so project, server, and persistent-cache resources are released before replacement.
  • Keep Utoopack's native process-global loader scheduler in the long-lived dev host and delegate Session Worker registration before loading @utoo/pack, preventing Worker creator already registered on the second Session.
  • Isolate build and dev process modes so a process-owned loader pool is never silently reused with incompatible environment semantics.
  • Integrate plugin-driven CLI shortcuts from current main into the Supervisor lifecycle.
  • Add supervisor, Session, watcher, generated-IR, adapter, native Utoopack A→B, cache-lock, scheduler, shortcut, and failure-recovery coverage.

Validation

  • npm run check-types
  • npm run lint
  • npm test (17 Turbo tasks passed; EV package 782 tests; Utoopack package 91 tests)
  • npm --workspace evjs-docs run build
  • git diff --check
  • Real jinni-explore validation with @utoo/pack@1.5.1: change page.config.ts, close Session A, start Session B on the same port, regenerate the manifest, and exit cleanly without cache-lock or scheduler-registration errors.

Risk / rollout

  • This breaks the internal @evjs/ev/_internal/build bundler adapter contract; repository Webpack and Utoopack adapters are migrated together.
  • Application configuration and plugin public APIs do not gain new fields.
  • Session replacement is intentionally fail-stop after shutdown begins; dev/server port changes still require restarting ev dev.
  • If Utoopack cannot confirm graceful shutdown within ten seconds, replacement stops instead of starting a second cache owner.
  • Utoopack loader workers are process-scoped and may be reused across dev Sessions. Programmatic build and dev calls in the same OS process now fail fast; normal CLI commands already run in separate processes.
  • The existing Utoopack limitation where an initial compile error can occur before its ready callback remains out of scope.

Reviewer notes

  • Review semantic fingerprint boundaries and watcher dependency handoff in the Supervisor.
  • Review strict old-Session close → canonical IR publish → new-Session start ordering.
  • Review the Utoopack graceful-close acknowledgement, SIGTERM bridge, timeout, cache-lock regression, and process-owned scheduler delegation.
  • Review scheduler failure propagation and build/dev process-mode guards.
  • Review shortcut detach/rebind behavior and adapter done/close behavior across failure and late callbacks.

Summary by CodeRabbit

  • New Features

    • Development now automatically prepares and replaces sessions when framework inputs change, while preserving the active server when changes are invalid or have no semantic effect.
    • Added interactive development CLI shortcuts with configuration and plugin support.
    • Utoopack now supports conventional server-rendered builds.
  • Bug Fixes

    • Improved recovery from framework updates, generated-state changes, watcher events, and development worker shutdowns.
    • Prevented stale build results from being published during session replacement.
  • Documentation

    • Updated development, bundler, plugin, configuration, and roadmap documentation.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a1ea094b-d0bd-4ae2-9a09-7050fe8a7768

📥 Commits

Reviewing files that changed from the base of the PR and between cc7a626 and cada431.

📒 Files selected for processing (60)
  • AGENTS.md
  • ARCHITECTURE.md
  • CHANGELOG.md
  • CONTRIBUTING.md
  • ROADMAP.md
  • docs/docs/architecture.md
  • docs/docs/config.md
  • docs/docs/dev.md
  • docs/docs/plugin-authoring.md
  • docs/docs/plugin-hooks.md
  • docs/docs/roadmap.md
  • docs/i18n/zh-Hans/docusaurus-plugin-content-docs/current/architecture.md
  • docs/i18n/zh-Hans/docusaurus-plugin-content-docs/current/config.md
  • docs/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dev.md
  • docs/i18n/zh-Hans/docusaurus-plugin-content-docs/current/plugin-authoring.md
  • docs/i18n/zh-Hans/docusaurus-plugin-content-docs/current/plugin-hooks.md
  • docs/i18n/zh-Hans/docusaurus-plugin-content-docs/current/roadmap.md
  • packages/bundler-utoopack/README.md
  • packages/bundler-utoopack/src/adapter/dev-worker-client.ts
  • packages/bundler-utoopack/src/adapter/dev-worker-scheduler.ts
  • packages/bundler-utoopack/src/adapter/dev-worker-shutdown.ts
  • packages/bundler-utoopack/src/adapter/dev-worker.ts
  • packages/bundler-utoopack/src/adapter/index.ts
  • packages/bundler-utoopack/tests/adapter.test.ts
  • packages/bundler-utoopack/tests/dev-worker-client.test.ts
  • packages/bundler-utoopack/tests/dev-worker-native-session.test.ts
  • packages/bundler-utoopack/tests/dev-worker-scheduler-mode.test.ts
  • packages/bundler-utoopack/tests/dev-worker-scheduler.test.ts
  • packages/bundler-utoopack/tests/dev-worker-shutdown.test.ts
  • packages/bundler-utoopack/tests/fixtures/dev-worker-client.mjs
  • packages/bundler-utoopack/tests/fixtures/dev-worker-native-session.mjs
  • packages/bundler-webpack/README.md
  • packages/bundler-webpack/src/adapter/index.ts
  • packages/bundler-webpack/tests/adapter.test.ts
  • packages/cli/src/inspect.ts
  • packages/cli/tests/inspect.test.ts
  • packages/cli/tests/plugin-hooks.test.ts
  • packages/cli/tests/programmatic.test.ts
  • packages/ev/src/_internal/build/analyze-and-materialize.ts
  • packages/ev/src/_internal/build/bundler.ts
  • packages/ev/src/_internal/build/cli-shortcuts.ts
  • packages/ev/src/_internal/build/commands.ts
  • packages/ev/src/_internal/build/dev-revision.ts
  • packages/ev/src/_internal/build/dev-session.ts
  • packages/ev/src/_internal/build/dev-supervisor.ts
  • packages/ev/src/_internal/build/dev-watch.ts
  • packages/ev/src/_internal/build/generated-contributions.ts
  • packages/ev/src/_internal/build/index.ts
  • packages/ev/src/_internal/build/inspect.ts
  • packages/ev/src/_internal/build/plugin-lifecycle.ts
  • packages/ev/src/config/index.ts
  • packages/ev/src/plugin/index.ts
  • packages/ev/tests/bundler-capabilities.test.ts
  • packages/ev/tests/commands-api-restart.test.ts
  • packages/ev/tests/commands.test.ts
  • packages/ev/tests/config.test.ts
  • packages/ev/tests/dev-session.test.ts
  • packages/ev/tests/dev-supervisor.test.ts
  • packages/ev/tests/dev-watch.test.ts
  • packages/ev/tests/package-surface.test.ts

📝 Walkthrough

Walkthrough

The PR replaces generation-based development updates with immutable Supervisor-managed Sessions. It adds semantic revision preparation, in-memory generated IR publication, revised Webpack and Utoopack adapter contracts, graceful Utoopack worker shutdown, and expanded lifecycle and watcher tests.

Changes

Development Session architecture

Layer / File(s) Summary
Session contracts and documented behavior
AGENTS.md, ARCHITECTURE.md, docs/docs/*, docs/i18n/zh-Hans/*, packages/ev/src/_internal/build/bundler.ts, packages/ev/src/config/index.ts
Development uses immutable Sessions managed by a Supervisor. Bundler capabilities now describe build capabilities only. BundlerAdapter.dev() returns a controller with origin, done, and close().
Revision preparation and supervision
packages/ev/src/_internal/build/dev-revision.ts, packages/ev/src/_internal/build/dev-session.ts, packages/ev/src/_internal/build/dev-supervisor.ts
Candidate revisions are prepared without writing .ev, fingerprinted semantically, and either reused or applied through complete Session replacement. Preparation failures preserve the active Session. Replacement failures stop development.
Semantic watching and generated IR
packages/ev/src/_internal/build/dev-watch.ts, packages/ev/src/_internal/build/generated-contributions.ts, packages/ev/src/_internal/build/analyze-and-materialize.ts
Watchers compare file contents, topology, symlinks, missing inputs, and ignored paths. Generated IR is rendered and validated in memory, then published as a complete .ev projection.
Webpack Session lifecycle
packages/bundler-webpack/src/adapter/index.ts, packages/bundler-webpack/tests/adapter.test.ts, packages/bundler-webpack/README.md
Webpack now uses abortable Session epochs and direct build-state processing. Ordinary module edits remain within bundler watch/HMR; semantic framework changes require Session replacement.
Utoopack worker lifecycle
packages/bundler-utoopack/src/adapter/*, packages/bundler-utoopack/tests/*
Utoopack development workers use process-wide scheduler ownership, graceful close acknowledgement, bounded shutdown, scheduler failure propagation, and queued build-facts processing.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant FileWatcher
  participant DevSupervisor
  participant DevRevision
  participant DevSession
  participant BundlerAdapter
  FileWatcher->>DevSupervisor: report framework input change
  DevSupervisor->>DevRevision: prepare candidate revision
  DevRevision-->>DevSupervisor: return semantic fingerprint and generated IR
  DevSupervisor->>DevSession: close active Session
  DevSession->>BundlerAdapter: close controller
  DevSupervisor->>DevSession: start replacement Session
  DevSession->>BundlerAdapter: start immutable controller
Loading

Possibly related PRs

  • afx-team/evjs#41: Shares the generated framework IR and .ev publication pipeline.
  • afx-team/evjs#45: Shares CLI shortcut propagation through plugin contexts.
  • afx-team/evjs#64: The current PR replaces its generation-aware development update mechanisms.

Suggested reviewers: fireairforce

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch xusd320/refactor-dev-supervisor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Move file watching and semantic revision scheduling into a long-lived supervisor. Replace in-place bundler plan transitions with complete immutable sessions, publish generated IR directly, and align the Webpack and Utoopack controller lifecycles.
@xusd320
xusd320 force-pushed the xusd320/refactor-dev-supervisor branch from c5c4957 to 2a69045 Compare August 10, 2026 02:23
Route Session shutdown through Utoopack's graceful cleanup and wait for an acknowledged worker exit before starting a replacement. Fail-stop on stuck shutdown instead of overlapping cache owners.
Keep Utoopack's native loader scheduler in the long-lived dev host so immutable Sessions can replace their Projects without registering stale Worker callbacks. Preserve build/dev process-mode isolation and fail-stop on loader infrastructure errors.
…supervisor

# Conflicts:
#	packages/bundler-utoopack/tests/adapter.test.ts
@xusd320
xusd320 marked this pull request as ready for review August 10, 2026 07:29
@xusd320
xusd320 merged commit 4411d79 into main Aug 10, 2026
1 of 2 checks passed
@xusd320
xusd320 deleted the xusd320/refactor-dev-supervisor branch August 10, 2026 07:30

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cada431cd8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +407 to +411
}).catch((error) => {
if (!this.closed) {
logger.error`Failed to process initial Utoopack dev build: ${error}`;
}
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Fail the session when initial fact publication fails

When onBuildFacts rejects—for example, because a plugin's output or afterBuild hook fails—this catch only logs the error while the controller's done promise remains pending. For a client-only plan no server-stats monitor is installed, so nothing retries processBuildFacts; the default Utoopack dev server remains advertised as ready even though its canonical HTML/manifest was rolled back or never emitted, and later client rebuilds cannot recover it. Reject the controller lifecycle or otherwise schedule a retry instead of swallowing this failure.

AGENTS.md reference: AGENTS.md:L94-L96

Useful? React with 👍 / 👎.

Comment on lines +240 to +245
releaseDistLock = await writeDevDistLock(options.cwd, options.plan.distDir);
unregisterDistExitCleanup = options.registerExitCleanup(() =>
releaseDistLock?.sync(),
);

controller = await options.bundler.dev({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Write the dist lock after adapter output cleanup

In a Webpack dev session this lock is created before bundler.dev() starts, but WebpackDevSession.start() immediately removes outputPaths.rootDir (the default dist directory), deleting dist/.evjs-dev.lock that was just written. The session then runs without the dist-lock safeguard, so any operation or external integration relying on assertNoActiveDevDistLock() can incorrectly treat the output as unused and overwrite it. Preserve or recreate the lock after the adapter's startup cleanup, as the previous ordering did.

Useful? React with 👍 / 👎.

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