openai / openai/codex

[Windows Desktop] Local automations stall: renderer capability true, main scheduler false, no reconciliation after a lost update

Open
#44,196 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app automations bug windows-os
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

What version of the Codex App are you using (From “About Codex” dialog)?

Windows MSIX package version 26.901.6511.0 (read from the installed package, not the About dialog).

What subscription do you have?

Not disclosed. The relevant runtime observation is that the renderer's resolved automations.local capability is true, with neither loading nor error, while the main-process scheduler retains false.

What platform is your computer?

Windows x64, OS build 10.0.26100.

What issue are you seeing?

Local automations stop being dispatched while the app is running. This report isolates a renderer-to-main capability synchronization failure before job dispatch, rather than an automation prompt, approval, or thread-resume failure.

Read-only inspection on September 10, 2026 found these states coexisting:

Component / field Observed value
Renderer automations.local isCapable=true, isLoading=false, isError=false
Capability-reporting component's effect dependencies, on the current committed React root [true]
Renderer localAutomationsScheduler bridge service Present
Main scheduler started true
Main scheduler disposed false
Main scheduler tick in progress false
Main scheduler local-automation capability false
Main scheduler interval Present

The controller was traced through its owning message handler and the native capability receiver to avoid confusing an abandoned scheduler object with the active instance. At inspection there was one primary window, and its ID matched the receiver origin. The current renderer RPC connection had no abort reason. The capability mismatch was observed repeatedly, not inferred from the UI's ACTIVE label alone.

The main scheduler's tick guard skips work while its stored capability is false. Thus a running timer does not imply that it scans or dispatches due jobs. Multiple ACTIVE jobs were overdue. All 22 local automation TOML files parsed successfully; 15 were ACTIVE and 7 PAUSED.

Evidence boundary: the present mismatch and the code path that allows it to persist are confirmed locally. The first lost/rejected capability update was not captured. I am NOT claiming that a particular window switch, bridge outage, or network event was the historical trigger, nor that all related automation reports have this cause.

What steps can reproduce the bug?

There is not yet a deterministic end-to-end GUI recipe for the original incident. The following are deterministic isolated failure-injection tests, not actions performed against the running app:

  1. Instantiate the installed scheduler and renderer capability-reporting component in a Node VM with in-memory jobs, mocked bridge/receiver, and virtual interval callbacks.
  2. Initialize renderer and main capability to false.
  3. On the renderer's transition to true, either:
    • temporarily make the optional bridge service unavailable for that one effect; or
    • let the receiver reject that update because its origin is not the current primary window.
  4. Restore bridge availability / primary-origin agreement, leave renderer capability true, render again, and invoke 20 scheduler ticks.
  5. No job is dispatched. Explicitly synchronize true inside the isolated test only, and dispatch begins.

This was tested by extracting the original installed scheduler (sl), reporting component (UFo), and receiver setCapability implementation, rather than only testing a rewritten model. The extraction harness and application bundles are not attached because this public report deliberately excludes local process-inspection tooling and private data.

Test using extracted functions New dispatches over 20 ticks Recorded warnings/errors Explicit true synchronization in test
Normal delivery 20 0 Already working
Optional service absent for the recovery update 0 0 One immediate dispatch
Receiver ignores non-primary recovery update 0 0 One immediate dispatch

The same results were reproduced across repeated executions. No production jobs were dispatched or resent by these tests.

Standalone reduced JavaScript reproducer of the synchronization mechanism

This dependency-free model illustrates the missing reconciliation. It is not the original app code and does not reproduce an entire desktop session. Run with Node.js; it performs no I/O except console output.

const assert = require('node:assert/strict');

function scenario(drop) {
  let uiCapability = false;
  let mainCapability = false;
  let bridgeReady = true;
  let isPrimary = true;
  let previousDependency;
  let dispatches = 0;

  function tick() {
    if (!mainCapability) return;
    dispatches++;
  }

  function receive(value) {
    if (!isPrimary) return; // ignored without an accepted-state acknowledgement
    if (mainCapability === value) return;
    mainCapability = value;
    if (value) tick();
  }

  function render() {
    if (Object.is(previousDependency, uiCapability)) return;
    previousDependency = uiCapability; // effect depends only on this boolean
    if (bridgeReady) receive(uiCapability);
  }

  render();
  if (drop === 'missing-service') bridgeReady = false;
  if (drop === 'non-primary') isPrimary = false;
  uiCapability = true;
  render();
  bridgeReady = true;
  isPrimary = true;

  const before = dispatches;
  for (let i = 0; i < 20; i++) { render(); tick(); }
  const duringTicks = dispatches - before;
  assert.equal(duringTicks, drop === 'normal' ? 20 : 0);
  const beforeReconcile = dispatches;
  receive(uiCapability); // test-only reconciliation, not a production workaround
  assert.equal(dispatches - beforeReconcile, drop === 'normal' ? 0 : 1);
  return { drop, duringTicks, afterReconcile: dispatches - beforeReconcile };
}

console.table(['normal', 'missing-service', 'non-primary'].map(scenario));
What is the expected behavior?

When the authoritative capability is true and the primary renderer and bridge are available, the scheduler should eventually converge to that state, or surface an actionable synchronization failure. A single lost capability update should not silently disable scheduling indefinitely while the UI remains capable.

The fix must preserve actual entitlement checks: this is a request for reliable state synchronization, not to force capability true or bypass a legitimate denial.

Additional information
Installed-code locations and mechanism

Bundle identity: app.asar SHA-256 E75BAE2B8A02F174C7CEEED6D631AAFF355E44F8AF5C798FA3628089F11D659E.

  • .vite/build/main-DpnWwRdP.js, sl: initializes the stored capability to false; the tick guard checks the in-progress flag and capability before doing work. setLocalAutomationsCapability updates the stored value and requests a tick on a transition to true.
  • Same bundle, pde.setCapability: accepts only the current primary-window origin. An ignored call does not communicate an accepted-state acknowledgement or retain the value for later primary-window reconciliation.
  • webview/assets/app-initial-f87238153a19.js, UFo: reports automations.local through a React effect depending only on the capability boolean. It calls the optional localAutomationsScheduler?.setCapability(...) service. An absent service is a no-op; rejection goes to a warning handler. This reporting path has no retry, accepted-state acknowledgement, or dependency on bridge readiness/reconnection or primary-window identity.

This is an edge-triggered update being used for state synchronization without a recovery path in the inspected reporting code. Re-rendering with the same true value does not re-run the effect, and the main timer cannot repair the stale false value itself. The isolated tests establish this failure mode; they do not establish which initial event occurred in the real session.

Potential fix / regression-test targets: acknowledge the applied value; reconcile on service readiness, reconnect, and primary-window changes; use bounded retry or reconciliation with observable failures; test one dropped update followed by stable true capability, as well as legitimate false/revoked capability. These are suggestions, not a patch verified against the live app.

Related reports and public fix search
  • #16938 and #17840: similar no-run/no-thread symptoms, but no confirmed renderer/main capability mismatch in the reports or comments reviewed.
  • #17893: its original report says next_run_at keeps advancing, whereas the affected schedules here remained overdue behind a false global scheduler gate.
  • #19011: creates an empty automation thread, which is a later failure boundary than this case.

These are related reports, not asserted duplicates. As of September 10, 2026, targeted searches of public issues/PRs and the official changelog did not identify a published fix for this specific synchronization mechanism. This does not rule out an unpublished/internal fix.

Diagnostics and this report were prepared with Codex assistance. Read-only runtime inspection and isolated tests were used; no app restart, process injection, capability override, automation configuration change, or production resend was performed. No credentials, private prompts, task identifiers, full logs, or process-memory dumps are included.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reporting component UFo in webview/assets/app-initial-f87238153a19.js and the scheduler and receiver paths in .vite/build/main-DpnWwRdP.js. Run the Node.js reduced reproducer, then trace how readiness, reconnects, and primary-window changes affect capability delivery. Done means a dropped update can recover without bypassing legitimate false or revoked capability, with regression coverage for both cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js, react
Domain
desktop, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.