Skip to content

Audit: production-mode-only code paths in core runtime #336

Description

@smiggleworth

Purpose

This is an audit task, not a bug report — it produces an inventory and spins off bugs, it doesn't fix anything itself.

Every branch gated on isDevelopmentEnvironment() (or an equivalent dev/prod flag) is a place where production behavior has never been deliberately verified — it just inherits whatever the code does when the guard is false. #333 (<For> key validation skipped in production) is a known instance; there are almost certainly others.

Procedure

  1. Run grep -rn "isDevelopmentEnvironment\|process.env.NODE_ENV\|__DEV__" src/ and enumerate every call site.
  2. For each site, answer explicitly: what does production do here, and is that acceptable? (e.g. "silently no-ops, and that's fine because X" vs. "silently no-ops and that's a real gap").
  3. Where the production behavior is a real gap, file a new issue in this milestone with Requirements/Acceptance Criteria/Steps to Reproduce (same format as Scheduler.waitForFlush() leaks waiter entries on timeout #332-Public API surface: documentation accuracy (actor-backed framing, root/data export split, state() dual API) #335), and link it from the checklist below.
  4. Where the production behavior is judged acceptable, note the one-sentence rationale inline — don't just leave it unmarked.

Definition of Done

Audit results (2026-08-24)

Prior confirmed production gap: #333 (For key validation); fixed before this audit. Current production fallbacks are exercised by tests/jsdom/dev_errors/prod-fallbacks.test.tsx and the production scenario/browser suites.

Site Production behavior and disposition
router/navigation-targets.ts:806 ✅ Same-path guard redirect still stops; only the developer warning is omitted.
router/navigation-targets.ts:839 ✅ Unmatched client navigation still returns without a route; only the developer warning is omitted.
router/navigation-targets.ts:1003 ✅ Unmatched pathname resolution still returns; only the developer warning is omitted.
ssr/boundaries.ts:129 ✅ Error details remain rendered but collapsed by default, avoiding disclosure while preserving the fallback.
ssr/component-runtime.ts:33,52,67,143 ✅ The strict nondeterminism monkey-patch is diagnostic-only; production renders normally without mutating globals.
ssr/render-sync.ts:41 ✅ SSR debug logging requires both non-production mode and explicit opt-in; render output is unchanged.
runtime/for-scopes.ts:359 ✅ Child scope disposal is still attempted; only cleanup-error console output is omitted.
runtime/for-signals.ts:424 ✅ Unknown-property diagnostics are omitted; proxy reads and reactive ownership behavior are unchanged.
boot/root-lifecycle.ts:139 ✅ Non-strict cleanup remains best-effort; production omits warnings, while strict cleanup still throws.
boot/root-lifecycle.ts:242 ✅ Prior-root cleanup remains best-effort during replacement; only the warning is omitted.
renderer/attributes.ts:31 dangerouslySetInnerHTML behavior is identical; production omits the security reminder.
runtime/component-lifecycle.ts:39 ✅ Illegal mount registration during bulk commit is ignored to protect commit progress; dev throws to expose misuse.
runtime/component-lifecycle.ts:56 ✅ Illegal commit registration during bulk commit is ignored to protect commit progress; dev throws to expose misuse.
runtime/component-cleanup.ts:52 ✅ Cleanup continues and captures errors when requested; otherwise production omits best-effort warnings.
runtime/component-cleanup.ts:135 ✅ Nested cleanup has the same capture-or-warn contract; production remains non-throwing.
control/case.ts:45 ✅ Standalone Match returns null; the usage error is diagnostic-only and production stays inert.
control/case.ts:107 ✅ Invalid children are skipped; the development error prevents mistakes without destabilizing production rendering.
runtime/component-internal.ts:291 ✅ Host-context enrichment is only for the development error message; the original error path remains intact.
runtime/component-internal.ts:414 ✅ Render timing is diagnostic telemetry and is intentionally compiled/runtime-disabled in production.
renderer/error-boundary-dom.ts:60 ✅ The same error details exist but default collapsed in production to reduce disclosure.
data/query-registry.ts:93 ✅ Missing SSR handler behavior is unchanged; repeated diagnostic recording is development-only.
runtime/for-reconcile.ts:51 ✅ Key validation is now performed by the production-safe path fixed in #333; this remaining helper is additional diagnostic validation.
runtime/component-commit.ts:68 ✅ Unhandled commit errors are swallowed only after boundary routing fails, preserving production progress; dev rethrows for diagnosis.
runtime/fastlane.ts:208 ✅ Scheduler snapshots are diagnostic-only and omitted from production cost.
runtime/fastlane.ts:222 ✅ Subscription-finalization invariant failures decline the optimization in production; dev surfaces the defect.
runtime/fastlane.ts:229 ✅ Fast-lane invariant validation is diagnostic-only; the normal commit result is already established.
runtime/fastlane.ts:324 ✅ A failed reorder optimization returns false, causing the safe general reconciliation path; dev rethrows.
runtime/scheduler.ts:170 ✅ Enqueue during bulk commit is ignored to preserve atomicity; dev throws to identify the invalid caller.
runtime/scheduler.ts:195 ✅ The bulk-commit flush prohibition is an invariant assertion; legal production scheduling follows the same path.
runtime/scheduler.ts:207 ✅ Per-task recursion accounting is a development diagnostic; production still has bounded flush progress and queue semantics.
runtime/scheduler.ts:301 ✅ Remaining-work assertion is diagnostic-only; legal runWithSyncProgress behavior is identical.
runtime/child-scope.ts:179 ✅ Rendering an already-disposed scope returns no vnode in production; dev throws to expose stale ownership.

Every current grep match is accounted for. No additional production correctness gap was found.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions