Skip to content

fix(ssr): keep cold module graphs alive while work progresses - #3027

Merged
kojiwakayama merged 21 commits into
mainfrom
debug/agentic-job-hydration
Jul 22, 2026
Merged

fix(ssr): keep cold module graphs alive while work progresses#3027
kojiwakayama merged 21 commits into
mainfrom
debug/agentic-job-hydration

Conversation

@kojiwakayama

Copy link
Copy Markdown
Contributor

Why

Cold concurrent SSR could exceed the fixed 10-second module-load deadline even while the transform graph was actively making progress. In the agentic job-submission app, six simultaneous cold requests all failed at about 10.1 seconds with module-loading timeouts.

Raising transform concurrency hid the symptom, but the default bounded queue still needed correct backpressure and liveness semantics.

What changed

Progress-aware module loading

  • Treat 10 seconds as an idle deadline and reset it only on meaningful module/transform progress.
  • Keep a non-resettable 45-second hard cap below the outer 60-second render budget.
  • Propagate progress through module loading, the transform pipeline, deep framework transforms, and shared cold-transform followers.
  • Detach timed-out callers with AbortSignal without cancelling a shared leader still needed by other requests.
  • Isolate throwing progress listeners.

Bounded cold-start coordination

  • Coalesce same-key cold transforms and broadcast leader progress to followers.
  • Wait for a live same-key SSR transform instead of deleting and retrying it after a fixed deadline.
  • Retry only after actual leader rejection and recheck the shared flight to avoid a retry stampede.
  • Increase semaphore acquisition patience from 500 ms to 5 seconds while keeping the default transform capacity at 3.

Browser and production boundaries

  • Remove server-hook-only imports and their transitive closure from browser artifacts while preserving client initializers in mixed declarations.
  • Keep server handlers, generated Deno shims, and SSR-only preload entries out of browser bundles.
  • Apply server boundaries before production splitting.
  • Preserve server data while statically rendering concrete Pages routes.
  • Ignore runtime coordination files in development watch invalidation.

Gate stability

  • Make the cycle-alias test compare against the exact returned artifact rather than assuming an unpadded hexadecimal hash always has eight characters.

Cold concurrency evidence

Same six cold requests, default transform capacity 3:

Route Before After
/chat 500 at ~10.1 s 200 at 8.245 s
/chat 500 at ~10.1 s 200 at 8.246 s
/jobs 500 at ~10.1 s 200 at 15.219 s
/ 500 at ~10.1 s 200 at 15.221 s
/review 500 at ~10.1 s 200 at 15.222 s
/jobs 500 at ~10.1 s 200 at 15.223 s

No module-load timeout or transform-capacity error occurred. A control run with transform capacity 200 completed in 7–14 seconds, confirming the remaining cold latency is bounded transform work rather than a deadlock. This PR does not raise the default concurrency.

Verification

  • Full pre-push gate: 2,545 tests / 21,263 steps, zero failures.
  • deno task verify:quick: formatting, lint, boundaries, docs, and typecheck pass.
  • Focused regression suite: 14 suites / 312 steps pass.
  • Cycle-alias stress: 50 consecutive module-loader suite runs pass.
  • deno task build:npm passes.
  • Consumer app npm run check: production build and all 53 tests pass.
  • Agent-browser: /chat renders and hydrates without page errors; warm desktop TTFB 75.5 ms, FCP/LCP 124 ms, CLS 0.

Relationship to #3025

This complements #3025 rather than replacing it. #3025 rewrites value imports from the root veryfront barrel to a browser-safe barrel. This PR removes hook-only server closure, prevents generated server shims/preloads from leaking into browser graphs, and fixes the cold SSR coordination and production-build paths. The branches can merge in either order.

Known follow-up

Pages Router production builds still do not expand getStaticPaths. Dynamic templates are excluded from SSG here so literal bracket routes are not emitted; full path expansion remains a separate follow-up.

Browser artifacts now remove the module-scope closure used only by server hooks while preserving client references and unrelated side-effect imports. Scope-aware free-variable analysis covers function parameters, hoisting, loops, switch cases, destructuring, JSX, and TypeScript wrappers.

Constraint: Browser stripping must not erase unrelated project import side effects
Rejected: Redirect every server barrel in the browser | direct project subpath imports would still leak
Confidence: high
Scope-risk: moderate
Directive: Add a focused scope regression before broadening the pruning analysis
Tested: browser-server-exports-strip.test.ts (72 steps); deno check; deno lint; deno fmt --check
Development HTML keeps explicit page, layout, JSX runtime, and release-manifest preloads, but no longer treats the legacy SSR route manifest as a browser preload source.

Constraint: SSR traversal may include server-only modules that must never reach the browser
Rejected: Filter known server module names | transitive project imports are open-ended
Confidence: high
Scope-risk: narrow
Tested: html-shell-generator.test.ts and html-shell-manifest.test.ts; deno check; deno lint; deno fmt --check
Both direct compilation and browser bundling target ES2022 so framework modules using top-level await remain valid through development hydration.

Constraint: The framework already ships modules that use top-level await
Rejected: Rewrite top-level await call sites | it duplicates module initialization semantics
Confidence: high
Scope-risk: narrow
Tested: compile.test.ts and browser-module-bundler.test.ts; deno check; deno lint; deno fmt --check
The watcher now ignores OMX runtime state and logs, matching other generated output directories and avoiding unrelated HMR work during agent-driven development.

Constraint: OMX writes runtime state inside the project tree
Confidence: high
Scope-risk: narrow
Tested: file-watch-setup.test.ts; deno check; deno lint; deno fmt --check
Same-key cache misses now join one in-flight computation while different keys remain concurrent. Failed flights are cleared so later requests can recover normally.

Constraint: Concurrent hydration requests can request the same uncached transform
Rejected: Raise the module-load timeout alone | duplicate cold work would remain and failures would only be delayed
Confidence: high
Scope-risk: narrow
Directive: Keep flight lifetime tied to the cache lifecycle and preserve retry after failure
Tested: transform-cache.test.ts; combined focused suite (183 steps); deno task typecheck
Pages Router collection now skips only files beneath the configured pages api directory while preserving a legitimate root api page. This prevents API handlers from entering browser code splitting and SSG rendering.

Constraint: pages/api.tsx remains a valid page at /api; only api directory descendants are handlers
Rejected: Exclude every /api URL | that would remove legitimate page routes and couple collection to URL naming
Confidence: high
Scope-risk: narrow
Tested: server/build-routes.test.ts (38 steps); deno task typecheck; deno check; deno lint; deno fmt --check
Project JavaScript and TypeScript modules now pass through the existing server-hook stripper before esbuild builds browser chunks. The splitter retains real source identities and owns local dependency resolution while hook-only Node and root-framework imports disappear before graph traversal.

Constraint: Full browser transforms rewrite imports for module-server delivery and cannot be fed directly into the chunk bundler
Rejected: Externalize Node builtins and the root framework barrel | that would hide and ship an invalid server dependency graph
Confidence: high
Scope-risk: moderate
Directive: Keep the splitter source transform limited to boundary stripping unless a virtual module resolver is added
Tested: real production CodeSplitter node:crypto/root-veryfront regression; splitter plugin tests; browser strip tests; deno task typecheck; deno check; deno lint; deno fmt --check
The production splitter can run before server bootstrap, so it now lazily registers the first-party Babel parser and verifies that lifecycle without test-only setup.

Constraint: Production builds may invoke the splitter without extension bootstrap.

Rejected: Keep parser registration in test setup | it masked the production lifecycle failure.

Confidence: high

Scope-risk: narrow

Tested: Code-splitter regression suite; framework targeted suite; linked app production build.
The router and UI barrels reach runtime core and color-mode modules that DNT had left connected to Node compatibility shims. Marking those emitted modules browser-safe removes that server graph at package build time.

Constraint: Browser code splitting must consume the published npm shape without externalizing all framework UI modules.

Rejected: Externalize every Veryfront client subpath | hides packaging defects and prevents normal chunk optimization.

Confidence: high

Scope-risk: narrow

Related: #3025

Tested: Browser-safe package tests; npm package build; esbuild shim scan; linked app production build.
Pages Router SSG now renders with a matching synthetic GET request and URL, allowing page and layout data hooks to receive their normal context. Dynamic route templates are excluded because this build path does not yet expand getStaticPaths and cannot render a literal bracket route.

Constraint: Static generation currently has no dynamic path expansion phase.

Rejected: Render bracket routes with empty params | produces invalid pages and crashes server-data hooks.

Confidence: high

Scope-risk: moderate

Directive: Add getStaticPaths expansion before including dynamic Pages routes in SSG collection.

Tested: Static-generation and route-collection tests; linked app production build and full npm run check.
Server-hook closure pruning now tracks each simple variable declarator independently, so removing a hook-only binding cannot erase a co-declared client side effect.

Constraint: Browser pruning must remain conservative for destructuring declarations.

Rejected: Keep the whole declaration | leaks hook-only server dependencies into browser graphs.

Confidence: high

Scope-risk: narrow

Tested: browser-server-exports-strip suite (73 steps); focused heartbeat/framework suite (226 steps)
Module loading now uses a 10-second idle deadline that resets only after concrete transform milestones, plus a non-resettable 45-second hard cap. Shared cold transforms broadcast progress to followers, while timed-out callers detach without cancelling work still needed by other renders.

Constraint: The outer render pipeline remains capped at 60 seconds.

Rejected: Raise the fixed 10-second timeout | would hide genuinely stalled module graphs.

Confidence: high

Scope-risk: moderate

Directive: Add progress marks only after meaningful work completes; never weaken the hard cap.

Tested: verify:quick; 14 targeted suites (304 steps); cold six-route comparison
Cold framework work can hold the default three transform permits longer than 500ms. Wait up to five seconds for bounded capacity, preserve active same-key singleflight work, and re-check coordination after a leader failure so followers cannot stampede into duplicate retries.

Constraint: Transform concurrency remains bounded by the existing semaphore and per-project limits.

Rejected: Raise the default transform capacity to 200 | the same six-route workload passes with the safe default of three when queueing is allowed to drain.

Confidence: high

Scope-risk: moderate

Directive: Do not timeout-delete live singleflight entries; only retry after the leader rejects.

Tested: transform concurrency validation; SSR loader suite; six cold concurrent routes returned 200 in 7.6-14.2 seconds
Module artifact hashes come from an unpadded 32-bit hexadecimal value, so randomized transformed paths can legitimately produce fewer than eight characters. Verify the alias against the exact returned artifact instead of assuming fixed hash width.

Constraint: Preserve the existing module filename and cache contract while removing a nondeterministic pre-push failure
Rejected: Pad every module hash to eight characters | would change production cache identities to satisfy a test-only assumption
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Cycle alias tests should compare the alias target with the loader result, not infer a fixed hash width
Tested: 50 consecutive module-loader suite runs; module-persistence suite; deno fmt --check
Not-tested: None
Copilot AI review requested due to automatic review settings July 22, 2026 17:24
@kojiwakayama
kojiwakayama requested a review from kwakayama as a code owner July 22, 2026 17:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves cold concurrent SSR reliability by making module-load timeouts progress-aware, coalescing shared cold transforms, and tightening browser/production boundaries so server-only graphs do not leak into client artifacts.

Changes:

  • Add progress-aware idle timeout + hard cap (withProgressTimeoutThrow) and wire module/transform progress events through the SSR module loader and transform pipeline.
  • Coalesce same-key cold transform work with singleflight, broadcast leader progress to followers, and detach aborted callers without cancelling shared leaders.
  • Strip server-only hook closures from browser bundles earlier in production splitting, adjust static generation route inclusion, and update build/watch tests accordingly.

Reviewed changes

Copilot reviewed 43 out of 43 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/validation/002-global-state/002.5-transform-concurrency.test.ts Updates semaphore timeout test to validate the new longer acquire patience under cold bursts.
src/transforms/progress.ts Introduces a minimal progress event/listener contract for transform milestones.
src/transforms/pipeline/types.ts Threads onProgress through pipeline options/context for milestone reporting.
src/transforms/pipeline/stages/ssr-vf-modules/transform.ts Emits progress milestones for framework transforms and cache hits; plumbs onProgress into framework source transforms.
src/transforms/pipeline/stages/ssr-vf-modules/index.ts Passes pipeline progress listener into framework module transform entrypoints and emits an entry milestone.
src/transforms/pipeline/stages/ssr-vf-modules/constants.ts Adds onProgress to the stage’s transform context.
src/transforms/pipeline/stages/compile.ts Raises esbuild transform target to es2022 to allow modern syntax (notably top-level await).
src/transforms/pipeline/stages/compile.test.ts Adds coverage for top-level await acceptance in compiled framework server modules.
src/transforms/pipeline/stages/browser-server-exports-strip.ts Makes server-only export stripping more scope-aware and more aggressive about removing hook-only imports from browser graphs.
src/transforms/pipeline/stages/browser-server-exports-strip.test.ts Expands regression coverage for hook-closure import stripping, shadowing, and destructuring/default edge cases.
src/transforms/pipeline/index.ts Emits progress milestones across pipeline lifecycle and stages.
src/transforms/pipeline/context.ts Wires onProgress from transform options into the created context.
src/transforms/esm/types.ts Adds onProgress to ESM transform options so module transforms can report milestones.
src/transforms/esm/transform-cache.ts Adds cold-miss singleflight coalescing plus progress broadcast/replay and abort-detach semantics.
src/transforms/esm/transform-cache.test.ts Adds tests for coalescing, progress fanout, listener isolation, abort detach, and failure cleanup.
src/server/shared/browser-module-bundler.ts Raises browser bundle target to es2022 to allow top-level await in browser modules.
src/server/shared/browser-module-bundler.test.ts Adds coverage for bundling browser modules that contain top-level await.
src/server/dev-server/file-watch-setup.ts Ignores .omx/ output to prevent dev watch invalidation loops.
src/server/dev-server/file-watch-setup.test.ts Tests .omx/ ignore behavior on POSIX and Windows paths.
src/server/build-routes.ts Excludes pages/api/* descendants and dynamic Pages Router routes from static generation.
src/server/build-routes.test.ts Tests the new Pages Router route filtering behavior (api descendants, dynamic routes).
src/rendering/utils/timeout-enforcement.test.ts Adds behavioral coverage for idle-reset + hard-cap timeouts.
src/rendering/utils/stream-utils.ts Adds withProgressTimeoutThrow and enriches TimeoutError with kind/lastProgress.
src/rendering/utils/index.ts Re-exports progress-timeout types and helper.
src/rendering/orchestrator/pipeline.ts Switches module loading to progress-aware timeout enforcement; plumbs progress into module loader config.
src/rendering/orchestrator/module-loader/module-transform-cache.ts Propagates progress and abort signals into the transform cache and ESM transform calls.
src/rendering/orchestrator/module-loader/index.ts Emits module-load progress milestones and supports cooperative cancellation via AbortSignal.
src/rendering/orchestrator/module-loader/index.test.ts Adjusts cycle-alias assertions to match the actual emitted artifact naming.
src/rendering/orchestrator/module-collection.ts Defines module-load idle timeout and hard-cap constants.
src/rendering/orchestrator/module-collection.test.ts Verifies updated module-load timeout constants.
src/modules/react-loader/ssr-module-loader/loader.ts Removes time-based in-progress retries and avoids deleting live leader state; relies on outer render deadlines.
src/modules/react-loader/ssr-module-loader/constants.ts Increases semaphore acquire timeout to 5s for cold backpressure.
src/html/html-shell-generator.ts Removes legacy route-manifest module preload hint generation from HTML shell.
src/html/html-shell-generator.test.ts Updates assertions to ensure SSR-derived legacy manifest modules are not emitted as preloads.
src/extensions/parser/defaults.ts Adds lazy registration for the default first-party CodeParser contract.
src/build/production-build/static-generation.ts Passes a synthetic Request/URL context into Pages Router static rendering.
src/build/production-build/static-generation.test.ts Tests synthetic request context propagation during Pages Router static generation.
src/build/bundler/code-splitter/splitter.ts Ensures default parser contracts exist before splitting production bundles.
src/build/bundler/code-splitter/splitter.test.ts Adds coverage that production browser chunks strip server-only page dependencies.
src/build/bundler/code-splitter/esbuild-plugin.ts Adds an onLoad hook to strip server-only exports from in-project JS/TS modules during browser bundling.
src/build/bundler/code-splitter/esbuild-plugin.test.ts Tests the new strip-loader behavior and handler registration count.
scripts/build/browser-safe-exports.test.ts Adds coverage ensuring certain runtime shims are included in browser-safe exports.
scripts/build/browser-safe-exports.mjs Adds missing client modules to the browser-safe export allowlist.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/transforms/esm/transform-cache.ts

@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: 9aec3a640b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/build/production-build/static-generation.ts
Comment thread src/transforms/pipeline/stages/browser-server-exports-strip.ts
Copilot AI review requested due to automatic review settings July 22, 2026 17:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 43 out of 43 changed files in this pull request and generated 2 comments.

Comment thread src/transforms/pipeline/stages/browser-server-exports-strip.ts
Comment thread src/build/bundler/code-splitter/esbuild-plugin.ts Outdated
Keep already-aborted followers listener-free, preserve ordinary import side effects when only hook-owned bindings are stripped, and make production Pages rendering explicitly static-data-only so request hooks cannot run during builds.

Constraint: Static generation may provide URL context to getStaticData but must never execute getServerData.

Rejected: Treat a synthetic GET request as safe build context | it can trigger request-only data and bake private state into static output.

Confidence: high

Scope-risk: moderate

Directive: Keep staticDataOnly as a strict getStaticData gate when extending render context.

Tested: 223 focused Deno test steps across transform cache, browser export stripping, static generation, render pipeline, and data fetching.

Not-tested: Full repository CI runs after the separate AG-UI work is complete.
Copilot AI review requested due to automatic review settings July 22, 2026 17:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 45 out of 45 changed files in this pull request and generated 2 comments.

Comment thread src/modules/react-loader/ssr-module-loader/loader.ts
Comment thread src/transforms/esm/transform-cache.ts Outdated
Layout and page data hooks can execute for the same pathname, so URL-only cache keys let the first module's props leak into the next. Thread the loaded module path through data fetching and include it in static cache identity.

Constraint: Preserve existing pathname and params cache behavior for callers without module identity
Rejected: Disable static data caching for layouts | removes valid production caching instead of fixing its identity
Confidence: high
Scope-risk: narrow
Directive: Every independently loaded data module must contribute its module path to static cache identity
Tested: Five focused suites, 152 steps; formatting and diff checks
Not-tested: Full repository suite deferred to pre-push
Copilot AI review requested due to automatic review settings July 22, 2026 18:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 49 out of 49 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/build/bundler/code-splitter/esbuild-plugin.ts:22

  • Use the internal import alias here instead of a deep relative path. The rest of this file already uses #veryfront/*, and keeping this consistent avoids brittle ../../../ paths when directories move.
import { stripServerOnlyExports } from "../../../transforms/pipeline/stages/browser-server-exports-strip.ts";

Direct project agents can now preserve hosted-style invoke_agent declarations as runtime-local tools, serialize that authored tool id across the project-agent boundary, and hydrate explicitly allowed first-party project-file tool schemas when the Veryfront API MCP catalog omits them. The branch also keeps the cold SSR progress and import-stripping review fixes in source and generated bridge artifacts.

Constraint: Direct AG-UI routes do not run inside the hosted chat envelope

Constraint: Explicit veryfront-api MCP allow policies must remain capability-minimal

Rejected: Add legacy agent_* wrapper tools beside invoke_agent | it widens the orchestrator tool surface and breaks hosted skill metadata

Rejected: Trust arbitrary missing remote tool names | fallback is limited to known first-party project-file primitives

Confidence: high

Scope-risk: moderate

Tested: deno test --allow-all src/agent/runtime/agent-delegation.test.ts src/agent/factory.test.ts src/agent/project/agent-runtime.test.ts src/agent/runtime/mcp-server-tool-sources.test.ts src/agent/ag-ui/handler.test.ts src/agent/runtime/chat-stream-handler.test.ts

Tested: deno task typecheck

Tested: deno task build:npm

Tested: linked app direct POST /api/ag-ui streamed to RunFinished without Unknown tool references
Copilot AI review requested due to automatic review settings July 22, 2026 19:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 84 out of 86 changed files in this pull request and generated no new comments.

Cold concurrent renders need progress-aware idle deadlines without letting abandoned transform leaders overwrite replacement cache state. Scope this branch back to SSR loading, serialize per-key transform publication across registry resets, and use identity-aware eviction so callers remain bounded without retry stampedes.

Constraint: A caller may detach at its hard deadline while shared transform work continues for other requests
Rejected: Delete in-progress state at every caller timeout | permits duplicate leaders and stale cache publication
Rejected: Publish cache writes without per-key ordering | an already-started stale backend write can finish after its replacement
Confidence: high
Scope-risk: moderate
Directive: Keep stale-flight eviction, generation identity checks, and per-key cache publication ordering coupled
Tested: deno test --allow-all loader.test.ts transform-cache.test.ts singleflight.test.ts (68 steps); deno check focused sources/tests; git diff --check HEAD^
Not-tested: Full repository test suite in this final review pass
Copilot AI review requested due to automatic review settings July 22, 2026 20:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 52 out of 52 changed files in this pull request and generated 2 comments.

Comment thread src/utils/singleflight.ts
Comment thread src/build/bundler/code-splitter/esbuild-plugin.ts
Bound repeated rejected-leader retries without adding an async leader-election gap, key static data by the URL query visible to hooks, isolate stale-eviction observers, and document the browser stripping and stage-wide timeout contracts. Canonicalize the splitter project root once so the production boundary check stays cheap.

Constraint: Slow healthy transforms must remain progress-aware and shared leaders must not be evicted by impatient followers

Rejected: Extract the follower loop into an async helper | an extra await before leader registration allowed concurrent callers to elect multiple leaders

Rejected: Sort query parameters in the cache key | URLSearchParams order is observable to getStaticData

Rejected: Retry rejected leaders until the outer render deadline | deterministic failures would amplify work and surface as misleading timeouts

Confidence: high

Scope-risk: moderate

Directive: Keep leader election synchronous when no flight exists; keep the one-replacement retry budget identity-guarded

Tested: 266 focused test steps; 20 consecutive SSR loader stress runs; changed-file format, lint, typecheck, and diff checks

Not-tested: Full repository pre-push gate reruns during push
Copilot AI review requested due to automatic review settings July 22, 2026 20:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 55 out of 55 changed files in this pull request and generated 1 comment.

Comment thread src/rendering/orchestrator/module-loader/index.ts
Module-load heartbeats now isolate listener failures while preserving the abort check ahead of every notification. A focused regression proves a throwing observer cannot fail a transform and a pre-aborted render never invokes the observer.

Constraint: Progress callbacks reset idle deadlines but are not part of transformed module semantics.

Rejected: Let observer errors propagate for visibility | diagnostic callbacks must not turn healthy module work into render failure.

Confidence: high

Scope-risk: narrow

Directive: Keep abort checks authoritative and ahead of any isolated progress notification.

Tested: module-loader index test (14 steps); targeted format and lint.

Not-tested: Full repository gate will run in the pre-push hook.
Copilot AI review requested due to automatic review settings July 22, 2026 20:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 55 out of 55 changed files in this pull request and generated no new comments.

@kojiwakayama
kojiwakayama enabled auto-merge (squash) July 22, 2026 21:03
@kojiwakayama
kojiwakayama merged commit 322596c into main Jul 22, 2026
29 checks passed
@kojiwakayama
kojiwakayama deleted the debug/agentic-job-hydration branch July 22, 2026 21:04
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.

3 participants