[5/5] fix(mobile): enable environments from the composer - #5599

Closed
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable
Closed

[5/5] fix(mobile): enable environments from the composer#5599
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable

Conversation

@DominicVonk

@DominicVonkDominicVonk commented Aug 7, 2026

Copy link
Copy Markdown

Problem

The composer status pill is already tappable, but it always dispatches a retry. In the red environment is not connected state shown for an available environment, the supervisor's desired state is false. Retrying cannot activate that environment, so tapping the pill appears to do nothing.

Solution

Choose the action from the typed connection phase and authoritative activation state:

  • disabled environments dispatch setEnabled(environmentId, true);
  • enabled offline, connecting, reconnecting, connected-syncing, and error states keep the existing retry behavior;
  • a missing route environment remains a no-op.

Activation is projected from the supervisor's desired flag rather than inferred from transient connection phase. The decision remains isolated in a small typed helper, and activation still flows through the shared environment registry and supervisor.

User impact

Tapping the red status pill directly enables and reconnects a disabled environment for the open thread. Users no longer need to leave the conversation and find the environment toggle in Settings.

Stack

This PR is 5/5. Depends on layers 1–4, ending with 4/5, #5596.

Please review and merge the upstream PRs in order from 1 through 5. Because this repository does not have native stacked PRs enabled and cross-fork branches cannot be upstream base refs, the upstream diffs are cumulative. The corresponding fork PRs use the true dependent bases and provide the clean per-layer diffs.

LayerUpstream PRClean stacked diff
1#5597 — network-status recoveryfork #1
2#5600 — persistent environment activationfork #2
3#5598 — environment-management UIfork #3
4#5596 — pasted pairing-link parsingfork #4
5#5599 — composer-pill activationfork #5

Validation

apps/mobile
Test Files 1 passed (1)
Tests 2 passed (2)
tsc --noEmit: passed
Physical iPhone
Signed development app installed: passed
Application launch through devicectl: passed
Updated Metro bundle loaded: passed

The focused test verifies that a disabled environment enables while enabled connection states retry. Integrated stack validation after rebasing onto latest upstream main: 14 test files passed with 124 tests; client-runtime, web, and mobile typechecks passed.

UI evidence

Before: disabled environmentAfter: tap enables and reconnects
Red not-connected composer pill before activationConversation available after tapping the composer pill

The after screenshot was captured on an iOS Simulator against disposable state. Tapping the red composer status pill enabled the saved environment; the disconnected placeholder and pill disappeared, and the thread became available without leaving the conversation.

Latest review pass

The underlying activation runtime now survives transient startup reconciliation failures, serializes registration with startup, clears stale disabled state on re-pair/platform restoration, and initializes presentation from authoritative desired state. Cloud switches disable without deleting registrations, and editing a disabled bearer environment preserves its activation state. The composer intentionally remains a no-op when its route environment no longer exists.

Latest integrated verification: client-runtime 47 test files / 598 tests passed; mobile 100 test files / 622 tests passed; client-runtime, web, and mobile typechecks passed.

Final review pass

The dependent runtime now updates registrations atomically while preserving activation, avoids transient connections for disabled edits, serializes activation controls with Save, and presents disabled environments without stale failures. The composer intentionally remains a no-op when its route environment no longer exists.

Latest verification: client-runtime 47 test files / 599 tests passed; mobile 100 test files / 622 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed. The Fallow new-only audit gate passed.

Rebased onto upstream main at 5661c6116 on 2026-08-07. Post-rebase verification: client-runtime 47 test files / 603 tests passed; mobile 100 test files / 624 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed.

Model: GPT-5; harness: Codex.


Note

Medium Risk
Changes connection catalog persistence, registry startup/reconciliation, and supervisor desired-state behavior across mobile, web, and desktop; incorrect activation handling could leave environments disconnected or fail startup until retry.

Overview
Adds persistent enable/disable for saved environments via disabledEnvironmentIds in the connection catalog and a ConnectionActivationStore on mobile, web, and desktop. Toggling off disconnects without removing the registration; presentation and workspace models now expose enabled separately from connection phase.

Mobile & web UI wire activation through EnvironmentActivationSwitch / settings edit dialogs (including bearer label/URL updates on web). Cloud rows use enable + retry instead of connect/disconnect semantics, with disabled environments shown as "Disabled" without stale error UI.

Thread composer (mobile): the status pill calls setEnabled(true) when the route environment is disabled (threadEnvironmentActivationAction), and keeps retry when already enabled—fixing taps that previously no-op’d because the supervisor had desired: false.

Runtime: registry startup retries on init failure; bearer profile updates go through updateRegistration; Connectivity.followNetworkStatus refreshes status on app wake with revision-safe application. Pairing forms gain parsePairingFields for pasted full URLs on blur/submit.

Reviewed by Cursor Bugbot for commit 3708623. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Enable environment activation toggling from the composer and settings UI

  • Adds a disabledEnvironmentIds field to the connection catalog document and a new ConnectionActivationStore persistence service to list, set, and reconcile per-environment enabled state across web, mobile, and desktop.
  • Extends EnvironmentRegistry with setEnabled and updateRegistration APIs; toggling enabled state connects or disconnects the supervisor immediately and is persisted atomically under an activation lock.
  • Startup now reconciles persisted activation state against known environments and retries with exponential backoff on failure.
  • Adds UI controls on mobile (ConnectionEnvironmentRow, CloudEnvironmentRowShell, EnvironmentActivationSwitch) and web (ConnectionsSettings) to enable/disable environments; disabled environments show an 'Enable' button and suppress connection errors.
  • Replaces direct connectivity.changes subscriptions with followNetworkStatus, which serializes wakeup-driven refreshes and deduplicates redundant status applications in RelayEnvironmentDiscovery, EnvironmentSupervisor, and the registry.
  • Risk: start on EnvironmentRegistry can now fail with a ConnectionPersistenceError due to activation store operations; callers that previously assumed a non-failing start will need to handle this.

Macroscope summarized 3708623.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ccd4ff46-8269-43eb-94eb-0c0425948e15

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
@DominicVonkDominicVonk changed the title fix(mobile): enable environments from the composer[5/5] fix(mobile): enable environments from the composerAug 7, 2026
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk

Copy link
Copy Markdown
Author

Clean per-layer diff in the native fork stack: DominicVonk#5 (fork stack #6). This upstream draft remains the contribution discussion and review target.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 5c46076 to 3230b19CompareAugust 7, 2026 10:31

@macroscopeappmacroscopeappBot 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.

Effect service conventions review: one issue found. In apps/mobile/src/connection/storage.ts the ConnectionPersistenceErroroperation labels were shifted when the new activation operations were introduced, so each store now reports a failure under the wrong operation. The equivalent code in apps/web/src/connection/storage.ts labels these correctly, which makes the mobile mapping the outlier. Everything else (the new ConnectionActivationStore tag, the registry setEnabled operation, the new environment-catalog:set-enabled command, and the followNetworkStatus helper whose dependencies are still acquired via yield* in each caller's make) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3230b19 to e51b5eeCompareAugust 7, 2026 10:33
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e51b5ee to 1300026CompareAugust 7, 2026 10:43
Comment threadpackages/client-runtime/src/connection/connectivity.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 1300026 to 3693f9eCompareAugust 7, 2026 10:46
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3693f9e to 6519a5aCompareAugust 7, 2026 10:55
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 6519a5a to f5b6861CompareAugust 7, 2026 11:02
@DominicVonk
DominicVonk marked this pull request as ready for review August 7, 2026 11:08
Comment threadapps/mobile/src/state/use-remote-environment-registry.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces a new feature allowing users to enable/disable environments from the mobile composer and settings UI. New user-facing capabilities with new components and state management warrant human review. Additionally, open review comments identify bugs in the activation switch (pending state not cleared on success) and edit dialog (silently enables disabled environments).

You can customize Macroscope's approvability policy. Learn more.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from f5b6861 to b97a4c0CompareAugust 7, 2026 11:27
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 39c9900 to 0887a16CompareAugust 7, 2026 11:37
Comment threadpackages/client-runtime/src/connection/registry.ts
Comment threadapps/mobile/src/features/threads/ThreadRouteScreen.tsx
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 0887a16 to 61edeb4CompareAugust 7, 2026 11:44
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 61edeb4 to fa883a2CompareAugust 7, 2026 12:00
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
[environment.displayUrl, environment.label, isSaving],
);

const handleSave = useCallback(async () => {

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.

🟡 Mediumsettings/ConnectionsSettings.tsx:1437

handleSave calls onUpdate to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches EnvironmentRegistry.register, which unconditionally calls activation.setEnabled(environmentId, true) and installs the entry with initiallyDesired: true, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ConnectionsSettings.tsx around line 1437:
`handleSave` calls `onUpdate` to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches `EnvironmentRegistry.register`, which unconditionally calls `activation.setEnabled(environmentId, true)` and installs the entry with `initiallyDesired: true`, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

Comment threadapps/mobile/src/features/connection/CloudEnvironmentRows.tsx
Comment threadpackages/client-runtime/src/connection/layer.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch 2 times, most recently from 8acb832 to 274a5ccCompareAugust 7, 2026 12:09
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 274a5cc to def0a30CompareAugust 7, 2026 12:13

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit def0a301f7a5d453c3af54fef652b4100d2671a1. Configure here.

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated

@macroscopeappmacroscopeappBot 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.

Effect service conventions: one issue found — newly added Effect.catchTag usages in packages/client-runtime/src/connection/onboarding.ts should use Effect.catchTags({ ... }).

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from def0a30 to e909e9cCompareAugust 7, 2026 15:44
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e909e9c to cae5dbbCompareAugust 7, 2026 15:48
Comment threadpackages/client-runtime/src/relay/discovery.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from cae5dbb to 3708623CompareAugust 7, 2026 16:18
Comment on lines +27 to +30
const result = await props.onValueChange(enabled);
if (!AsyncResult.isSuccess(result)) {
setPending((current) => (current === request ? null : current));
}

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.

🟡 Mediumconnection/EnvironmentActivationSwitch.tsx:27

A successful toggle leaves pending set indefinitely, so if props.enabled later cycles back to the request's previous value, the switch re-enters a phantom pending state: isPending becomes true, the switch displays the stale requested value, and disables itself even though no request is in flight. The success path only clears pending on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

 const result = await props.onValueChange(enabled);
- if (!AsyncResult.isSuccess(result)) {+ if (AsyncResult.isSuccess(result)) {+ setPending((current) => (current === request ? null : current));+ } else {
setPending((current) => (current === request ? null : current));
}
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/features/connection/EnvironmentActivationSwitch.tsx around lines 27-30:
A successful toggle leaves `pending` set indefinitely, so if `props.enabled` later cycles back to the request's `previous` value, the switch re-enters a phantom pending state: `isPending` becomes `true`, the switch displays the stale `requested` value, and disables itself even though no request is in flight. The success path only clears `pending` on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

@DominicVonk

Copy link
Copy Markdown
Author

Superseded by #5598. The composer enable action now ships with the durable activation model and management UI in one independently mergeable PR based directly on main.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DominicVonk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[5/5] fix(mobile): enable environments from the composer - #5599

Closed
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable
Closed

[5/5] fix(mobile): enable environments from the composer#5599
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable

Conversation

@DominicVonk

@DominicVonkDominicVonk commented Aug 7, 2026

Copy link
Copy Markdown

Problem

The composer status pill is already tappable, but it always dispatches a retry. In the red environment is not connected state shown for an available environment, the supervisor's desired state is false. Retrying cannot activate that environment, so tapping the pill appears to do nothing.

Solution

Choose the action from the typed connection phase and authoritative activation state:

  • disabled environments dispatch setEnabled(environmentId, true);
  • enabled offline, connecting, reconnecting, connected-syncing, and error states keep the existing retry behavior;
  • a missing route environment remains a no-op.

Activation is projected from the supervisor's desired flag rather than inferred from transient connection phase. The decision remains isolated in a small typed helper, and activation still flows through the shared environment registry and supervisor.

User impact

Tapping the red status pill directly enables and reconnects a disabled environment for the open thread. Users no longer need to leave the conversation and find the environment toggle in Settings.

Stack

This PR is 5/5. Depends on layers 1–4, ending with 4/5, #5596.

Please review and merge the upstream PRs in order from 1 through 5. Because this repository does not have native stacked PRs enabled and cross-fork branches cannot be upstream base refs, the upstream diffs are cumulative. The corresponding fork PRs use the true dependent bases and provide the clean per-layer diffs.

LayerUpstream PRClean stacked diff
1#5597 — network-status recoveryfork #1
2#5600 — persistent environment activationfork #2
3#5598 — environment-management UIfork #3
4#5596 — pasted pairing-link parsingfork #4
5#5599 — composer-pill activationfork #5

Validation

apps/mobile
Test Files 1 passed (1)
Tests 2 passed (2)
tsc --noEmit: passed
Physical iPhone
Signed development app installed: passed
Application launch through devicectl: passed
Updated Metro bundle loaded: passed

The focused test verifies that a disabled environment enables while enabled connection states retry. Integrated stack validation after rebasing onto latest upstream main: 14 test files passed with 124 tests; client-runtime, web, and mobile typechecks passed.

UI evidence

Before: disabled environmentAfter: tap enables and reconnects
Red not-connected composer pill before activationConversation available after tapping the composer pill

The after screenshot was captured on an iOS Simulator against disposable state. Tapping the red composer status pill enabled the saved environment; the disconnected placeholder and pill disappeared, and the thread became available without leaving the conversation.

Latest review pass

The underlying activation runtime now survives transient startup reconciliation failures, serializes registration with startup, clears stale disabled state on re-pair/platform restoration, and initializes presentation from authoritative desired state. Cloud switches disable without deleting registrations, and editing a disabled bearer environment preserves its activation state. The composer intentionally remains a no-op when its route environment no longer exists.

Latest integrated verification: client-runtime 47 test files / 598 tests passed; mobile 100 test files / 622 tests passed; client-runtime, web, and mobile typechecks passed.

Final review pass

The dependent runtime now updates registrations atomically while preserving activation, avoids transient connections for disabled edits, serializes activation controls with Save, and presents disabled environments without stale failures. The composer intentionally remains a no-op when its route environment no longer exists.

Latest verification: client-runtime 47 test files / 599 tests passed; mobile 100 test files / 622 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed. The Fallow new-only audit gate passed.

Rebased onto upstream main at 5661c6116 on 2026-08-07. Post-rebase verification: client-runtime 47 test files / 603 tests passed; mobile 100 test files / 624 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed.

Model: GPT-5; harness: Codex.


Note

Medium Risk
Changes connection catalog persistence, registry startup/reconciliation, and supervisor desired-state behavior across mobile, web, and desktop; incorrect activation handling could leave environments disconnected or fail startup until retry.

Overview
Adds persistent enable/disable for saved environments via disabledEnvironmentIds in the connection catalog and a ConnectionActivationStore on mobile, web, and desktop. Toggling off disconnects without removing the registration; presentation and workspace models now expose enabled separately from connection phase.

Mobile & web UI wire activation through EnvironmentActivationSwitch / settings edit dialogs (including bearer label/URL updates on web). Cloud rows use enable + retry instead of connect/disconnect semantics, with disabled environments shown as "Disabled" without stale error UI.

Thread composer (mobile): the status pill calls setEnabled(true) when the route environment is disabled (threadEnvironmentActivationAction), and keeps retry when already enabled—fixing taps that previously no-op’d because the supervisor had desired: false.

Runtime: registry startup retries on init failure; bearer profile updates go through updateRegistration; Connectivity.followNetworkStatus refreshes status on app wake with revision-safe application. Pairing forms gain parsePairingFields for pasted full URLs on blur/submit.

Reviewed by Cursor Bugbot for commit 3708623. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Enable environment activation toggling from the composer and settings UI

  • Adds a disabledEnvironmentIds field to the connection catalog document and a new ConnectionActivationStore persistence service to list, set, and reconcile per-environment enabled state across web, mobile, and desktop.
  • Extends EnvironmentRegistry with setEnabled and updateRegistration APIs; toggling enabled state connects or disconnects the supervisor immediately and is persisted atomically under an activation lock.
  • Startup now reconciles persisted activation state against known environments and retries with exponential backoff on failure.
  • Adds UI controls on mobile (ConnectionEnvironmentRow, CloudEnvironmentRowShell, EnvironmentActivationSwitch) and web (ConnectionsSettings) to enable/disable environments; disabled environments show an 'Enable' button and suppress connection errors.
  • Replaces direct connectivity.changes subscriptions with followNetworkStatus, which serializes wakeup-driven refreshes and deduplicates redundant status applications in RelayEnvironmentDiscovery, EnvironmentSupervisor, and the registry.
  • Risk: start on EnvironmentRegistry can now fail with a ConnectionPersistenceError due to activation store operations; callers that previously assumed a non-failing start will need to handle this.

Macroscope summarized 3708623.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ccd4ff46-8269-43eb-94eb-0c0425948e15

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
@DominicVonkDominicVonk changed the title fix(mobile): enable environments from the composer[5/5] fix(mobile): enable environments from the composerAug 7, 2026
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk

Copy link
Copy Markdown
Author

Clean per-layer diff in the native fork stack: DominicVonk#5 (fork stack #6). This upstream draft remains the contribution discussion and review target.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 5c46076 to 3230b19CompareAugust 7, 2026 10:31

@macroscopeappmacroscopeappBot 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.

Effect service conventions review: one issue found. In apps/mobile/src/connection/storage.ts the ConnectionPersistenceErroroperation labels were shifted when the new activation operations were introduced, so each store now reports a failure under the wrong operation. The equivalent code in apps/web/src/connection/storage.ts labels these correctly, which makes the mobile mapping the outlier. Everything else (the new ConnectionActivationStore tag, the registry setEnabled operation, the new environment-catalog:set-enabled command, and the followNetworkStatus helper whose dependencies are still acquired via yield* in each caller's make) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3230b19 to e51b5eeCompareAugust 7, 2026 10:33
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e51b5ee to 1300026CompareAugust 7, 2026 10:43
Comment threadpackages/client-runtime/src/connection/connectivity.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 1300026 to 3693f9eCompareAugust 7, 2026 10:46
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3693f9e to 6519a5aCompareAugust 7, 2026 10:55
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 6519a5a to f5b6861CompareAugust 7, 2026 11:02
@DominicVonk
DominicVonk marked this pull request as ready for review August 7, 2026 11:08
Comment threadapps/mobile/src/state/use-remote-environment-registry.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces a new feature allowing users to enable/disable environments from the mobile composer and settings UI. New user-facing capabilities with new components and state management warrant human review. Additionally, open review comments identify bugs in the activation switch (pending state not cleared on success) and edit dialog (silently enables disabled environments).

You can customize Macroscope's approvability policy. Learn more.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from f5b6861 to b97a4c0CompareAugust 7, 2026 11:27
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 39c9900 to 0887a16CompareAugust 7, 2026 11:37
Comment threadpackages/client-runtime/src/connection/registry.ts
Comment threadapps/mobile/src/features/threads/ThreadRouteScreen.tsx
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 0887a16 to 61edeb4CompareAugust 7, 2026 11:44
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 61edeb4 to fa883a2CompareAugust 7, 2026 12:00
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
[environment.displayUrl, environment.label, isSaving],
);

const handleSave = useCallback(async () => {

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.

🟡 Mediumsettings/ConnectionsSettings.tsx:1437

handleSave calls onUpdate to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches EnvironmentRegistry.register, which unconditionally calls activation.setEnabled(environmentId, true) and installs the entry with initiallyDesired: true, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ConnectionsSettings.tsx around line 1437:
`handleSave` calls `onUpdate` to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches `EnvironmentRegistry.register`, which unconditionally calls `activation.setEnabled(environmentId, true)` and installs the entry with `initiallyDesired: true`, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

Comment threadapps/mobile/src/features/connection/CloudEnvironmentRows.tsx
Comment threadpackages/client-runtime/src/connection/layer.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch 2 times, most recently from 8acb832 to 274a5ccCompareAugust 7, 2026 12:09
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 274a5cc to def0a30CompareAugust 7, 2026 12:13

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit def0a301f7a5d453c3af54fef652b4100d2671a1. Configure here.

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated

@macroscopeappmacroscopeappBot 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.

Effect service conventions: one issue found — newly added Effect.catchTag usages in packages/client-runtime/src/connection/onboarding.ts should use Effect.catchTags({ ... }).

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from def0a30 to e909e9cCompareAugust 7, 2026 15:44
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e909e9c to cae5dbbCompareAugust 7, 2026 15:48
Comment threadpackages/client-runtime/src/relay/discovery.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from cae5dbb to 3708623CompareAugust 7, 2026 16:18
Comment on lines +27 to +30
const result = await props.onValueChange(enabled);
if (!AsyncResult.isSuccess(result)) {
setPending((current) => (current === request ? null : current));
}

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.

🟡 Mediumconnection/EnvironmentActivationSwitch.tsx:27

A successful toggle leaves pending set indefinitely, so if props.enabled later cycles back to the request's previous value, the switch re-enters a phantom pending state: isPending becomes true, the switch displays the stale requested value, and disables itself even though no request is in flight. The success path only clears pending on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

 const result = await props.onValueChange(enabled);
- if (!AsyncResult.isSuccess(result)) {+ if (AsyncResult.isSuccess(result)) {+ setPending((current) => (current === request ? null : current));+ } else {
setPending((current) => (current === request ? null : current));
}
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/features/connection/EnvironmentActivationSwitch.tsx around lines 27-30:
A successful toggle leaves `pending` set indefinitely, so if `props.enabled` later cycles back to the request's `previous` value, the switch re-enters a phantom pending state: `isPending` becomes `true`, the switch displays the stale `requested` value, and disables itself even though no request is in flight. The success path only clears `pending` on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

@DominicVonk

Copy link
Copy Markdown
Author

Superseded by #5598. The composer enable action now ships with the durable activation model and management UI in one independently mergeable PR based directly on main.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DominicVonk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[5/5] fix(mobile): enable environments from the composer - #5599

Closed
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable
Closed

[5/5] fix(mobile): enable environments from the composer#5599
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable

Conversation

@DominicVonk

@DominicVonkDominicVonk commented Aug 7, 2026

Copy link
Copy Markdown

Problem

The composer status pill is already tappable, but it always dispatches a retry. In the red environment is not connected state shown for an available environment, the supervisor's desired state is false. Retrying cannot activate that environment, so tapping the pill appears to do nothing.

Solution

Choose the action from the typed connection phase and authoritative activation state:

  • disabled environments dispatch setEnabled(environmentId, true);
  • enabled offline, connecting, reconnecting, connected-syncing, and error states keep the existing retry behavior;
  • a missing route environment remains a no-op.

Activation is projected from the supervisor's desired flag rather than inferred from transient connection phase. The decision remains isolated in a small typed helper, and activation still flows through the shared environment registry and supervisor.

User impact

Tapping the red status pill directly enables and reconnects a disabled environment for the open thread. Users no longer need to leave the conversation and find the environment toggle in Settings.

Stack

This PR is 5/5. Depends on layers 1–4, ending with 4/5, #5596.

Please review and merge the upstream PRs in order from 1 through 5. Because this repository does not have native stacked PRs enabled and cross-fork branches cannot be upstream base refs, the upstream diffs are cumulative. The corresponding fork PRs use the true dependent bases and provide the clean per-layer diffs.

LayerUpstream PRClean stacked diff
1#5597 — network-status recoveryfork #1
2#5600 — persistent environment activationfork #2
3#5598 — environment-management UIfork #3
4#5596 — pasted pairing-link parsingfork #4
5#5599 — composer-pill activationfork #5

Validation

apps/mobile
Test Files 1 passed (1)
Tests 2 passed (2)
tsc --noEmit: passed
Physical iPhone
Signed development app installed: passed
Application launch through devicectl: passed
Updated Metro bundle loaded: passed

The focused test verifies that a disabled environment enables while enabled connection states retry. Integrated stack validation after rebasing onto latest upstream main: 14 test files passed with 124 tests; client-runtime, web, and mobile typechecks passed.

UI evidence

Before: disabled environmentAfter: tap enables and reconnects
Red not-connected composer pill before activationConversation available after tapping the composer pill

The after screenshot was captured on an iOS Simulator against disposable state. Tapping the red composer status pill enabled the saved environment; the disconnected placeholder and pill disappeared, and the thread became available without leaving the conversation.

Latest review pass

The underlying activation runtime now survives transient startup reconciliation failures, serializes registration with startup, clears stale disabled state on re-pair/platform restoration, and initializes presentation from authoritative desired state. Cloud switches disable without deleting registrations, and editing a disabled bearer environment preserves its activation state. The composer intentionally remains a no-op when its route environment no longer exists.

Latest integrated verification: client-runtime 47 test files / 598 tests passed; mobile 100 test files / 622 tests passed; client-runtime, web, and mobile typechecks passed.

Final review pass

The dependent runtime now updates registrations atomically while preserving activation, avoids transient connections for disabled edits, serializes activation controls with Save, and presents disabled environments without stale failures. The composer intentionally remains a no-op when its route environment no longer exists.

Latest verification: client-runtime 47 test files / 599 tests passed; mobile 100 test files / 622 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed. The Fallow new-only audit gate passed.

Rebased onto upstream main at 5661c6116 on 2026-08-07. Post-rebase verification: client-runtime 47 test files / 603 tests passed; mobile 100 test files / 624 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed.

Model: GPT-5; harness: Codex.


Note

Medium Risk
Changes connection catalog persistence, registry startup/reconciliation, and supervisor desired-state behavior across mobile, web, and desktop; incorrect activation handling could leave environments disconnected or fail startup until retry.

Overview
Adds persistent enable/disable for saved environments via disabledEnvironmentIds in the connection catalog and a ConnectionActivationStore on mobile, web, and desktop. Toggling off disconnects without removing the registration; presentation and workspace models now expose enabled separately from connection phase.

Mobile & web UI wire activation through EnvironmentActivationSwitch / settings edit dialogs (including bearer label/URL updates on web). Cloud rows use enable + retry instead of connect/disconnect semantics, with disabled environments shown as "Disabled" without stale error UI.

Thread composer (mobile): the status pill calls setEnabled(true) when the route environment is disabled (threadEnvironmentActivationAction), and keeps retry when already enabled—fixing taps that previously no-op’d because the supervisor had desired: false.

Runtime: registry startup retries on init failure; bearer profile updates go through updateRegistration; Connectivity.followNetworkStatus refreshes status on app wake with revision-safe application. Pairing forms gain parsePairingFields for pasted full URLs on blur/submit.

Reviewed by Cursor Bugbot for commit 3708623. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Enable environment activation toggling from the composer and settings UI

  • Adds a disabledEnvironmentIds field to the connection catalog document and a new ConnectionActivationStore persistence service to list, set, and reconcile per-environment enabled state across web, mobile, and desktop.
  • Extends EnvironmentRegistry with setEnabled and updateRegistration APIs; toggling enabled state connects or disconnects the supervisor immediately and is persisted atomically under an activation lock.
  • Startup now reconciles persisted activation state against known environments and retries with exponential backoff on failure.
  • Adds UI controls on mobile (ConnectionEnvironmentRow, CloudEnvironmentRowShell, EnvironmentActivationSwitch) and web (ConnectionsSettings) to enable/disable environments; disabled environments show an 'Enable' button and suppress connection errors.
  • Replaces direct connectivity.changes subscriptions with followNetworkStatus, which serializes wakeup-driven refreshes and deduplicates redundant status applications in RelayEnvironmentDiscovery, EnvironmentSupervisor, and the registry.
  • Risk: start on EnvironmentRegistry can now fail with a ConnectionPersistenceError due to activation store operations; callers that previously assumed a non-failing start will need to handle this.

Macroscope summarized 3708623.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ccd4ff46-8269-43eb-94eb-0c0425948e15

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
@DominicVonkDominicVonk changed the title fix(mobile): enable environments from the composer[5/5] fix(mobile): enable environments from the composerAug 7, 2026
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk

Copy link
Copy Markdown
Author

Clean per-layer diff in the native fork stack: DominicVonk#5 (fork stack #6). This upstream draft remains the contribution discussion and review target.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 5c46076 to 3230b19CompareAugust 7, 2026 10:31

@macroscopeappmacroscopeappBot 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.

Effect service conventions review: one issue found. In apps/mobile/src/connection/storage.ts the ConnectionPersistenceErroroperation labels were shifted when the new activation operations were introduced, so each store now reports a failure under the wrong operation. The equivalent code in apps/web/src/connection/storage.ts labels these correctly, which makes the mobile mapping the outlier. Everything else (the new ConnectionActivationStore tag, the registry setEnabled operation, the new environment-catalog:set-enabled command, and the followNetworkStatus helper whose dependencies are still acquired via yield* in each caller's make) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3230b19 to e51b5eeCompareAugust 7, 2026 10:33
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e51b5ee to 1300026CompareAugust 7, 2026 10:43
Comment threadpackages/client-runtime/src/connection/connectivity.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 1300026 to 3693f9eCompareAugust 7, 2026 10:46
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3693f9e to 6519a5aCompareAugust 7, 2026 10:55
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 6519a5a to f5b6861CompareAugust 7, 2026 11:02
@DominicVonk
DominicVonk marked this pull request as ready for review August 7, 2026 11:08
Comment threadapps/mobile/src/state/use-remote-environment-registry.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces a new feature allowing users to enable/disable environments from the mobile composer and settings UI. New user-facing capabilities with new components and state management warrant human review. Additionally, open review comments identify bugs in the activation switch (pending state not cleared on success) and edit dialog (silently enables disabled environments).

You can customize Macroscope's approvability policy. Learn more.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from f5b6861 to b97a4c0CompareAugust 7, 2026 11:27
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 39c9900 to 0887a16CompareAugust 7, 2026 11:37
Comment threadpackages/client-runtime/src/connection/registry.ts
Comment threadapps/mobile/src/features/threads/ThreadRouteScreen.tsx
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 0887a16 to 61edeb4CompareAugust 7, 2026 11:44
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 61edeb4 to fa883a2CompareAugust 7, 2026 12:00
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
[environment.displayUrl, environment.label, isSaving],
);

const handleSave = useCallback(async () => {

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.

🟡 Mediumsettings/ConnectionsSettings.tsx:1437

handleSave calls onUpdate to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches EnvironmentRegistry.register, which unconditionally calls activation.setEnabled(environmentId, true) and installs the entry with initiallyDesired: true, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ConnectionsSettings.tsx around line 1437:
`handleSave` calls `onUpdate` to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches `EnvironmentRegistry.register`, which unconditionally calls `activation.setEnabled(environmentId, true)` and installs the entry with `initiallyDesired: true`, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

Comment threadapps/mobile/src/features/connection/CloudEnvironmentRows.tsx
Comment threadpackages/client-runtime/src/connection/layer.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch 2 times, most recently from 8acb832 to 274a5ccCompareAugust 7, 2026 12:09
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 274a5cc to def0a30CompareAugust 7, 2026 12:13

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit def0a301f7a5d453c3af54fef652b4100d2671a1. Configure here.

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated

@macroscopeappmacroscopeappBot 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.

Effect service conventions: one issue found — newly added Effect.catchTag usages in packages/client-runtime/src/connection/onboarding.ts should use Effect.catchTags({ ... }).

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from def0a30 to e909e9cCompareAugust 7, 2026 15:44
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e909e9c to cae5dbbCompareAugust 7, 2026 15:48
Comment threadpackages/client-runtime/src/relay/discovery.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from cae5dbb to 3708623CompareAugust 7, 2026 16:18
Comment on lines +27 to +30
const result = await props.onValueChange(enabled);
if (!AsyncResult.isSuccess(result)) {
setPending((current) => (current === request ? null : current));
}

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.

🟡 Mediumconnection/EnvironmentActivationSwitch.tsx:27

A successful toggle leaves pending set indefinitely, so if props.enabled later cycles back to the request's previous value, the switch re-enters a phantom pending state: isPending becomes true, the switch displays the stale requested value, and disables itself even though no request is in flight. The success path only clears pending on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

 const result = await props.onValueChange(enabled);
- if (!AsyncResult.isSuccess(result)) {+ if (AsyncResult.isSuccess(result)) {+ setPending((current) => (current === request ? null : current));+ } else {
setPending((current) => (current === request ? null : current));
}
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/features/connection/EnvironmentActivationSwitch.tsx around lines 27-30:
A successful toggle leaves `pending` set indefinitely, so if `props.enabled` later cycles back to the request's `previous` value, the switch re-enters a phantom pending state: `isPending` becomes `true`, the switch displays the stale `requested` value, and disables itself even though no request is in flight. The success path only clears `pending` on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

@DominicVonk

Copy link
Copy Markdown
Author

Superseded by #5598. The composer enable action now ships with the durable activation model and management UI in one independently mergeable PR based directly on main.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DominicVonk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[5/5] fix(mobile): enable environments from the composer - #5599

Closed
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable
Closed

[5/5] fix(mobile): enable environments from the composer#5599
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable

Conversation

@DominicVonk

@DominicVonkDominicVonk commented Aug 7, 2026

Copy link
Copy Markdown

Problem

The composer status pill is already tappable, but it always dispatches a retry. In the red environment is not connected state shown for an available environment, the supervisor's desired state is false. Retrying cannot activate that environment, so tapping the pill appears to do nothing.

Solution

Choose the action from the typed connection phase and authoritative activation state:

  • disabled environments dispatch setEnabled(environmentId, true);
  • enabled offline, connecting, reconnecting, connected-syncing, and error states keep the existing retry behavior;
  • a missing route environment remains a no-op.

Activation is projected from the supervisor's desired flag rather than inferred from transient connection phase. The decision remains isolated in a small typed helper, and activation still flows through the shared environment registry and supervisor.

User impact

Tapping the red status pill directly enables and reconnects a disabled environment for the open thread. Users no longer need to leave the conversation and find the environment toggle in Settings.

Stack

This PR is 5/5. Depends on layers 1–4, ending with 4/5, #5596.

Please review and merge the upstream PRs in order from 1 through 5. Because this repository does not have native stacked PRs enabled and cross-fork branches cannot be upstream base refs, the upstream diffs are cumulative. The corresponding fork PRs use the true dependent bases and provide the clean per-layer diffs.

LayerUpstream PRClean stacked diff
1#5597 — network-status recoveryfork #1
2#5600 — persistent environment activationfork #2
3#5598 — environment-management UIfork #3
4#5596 — pasted pairing-link parsingfork #4
5#5599 — composer-pill activationfork #5

Validation

apps/mobile
Test Files 1 passed (1)
Tests 2 passed (2)
tsc --noEmit: passed
Physical iPhone
Signed development app installed: passed
Application launch through devicectl: passed
Updated Metro bundle loaded: passed

The focused test verifies that a disabled environment enables while enabled connection states retry. Integrated stack validation after rebasing onto latest upstream main: 14 test files passed with 124 tests; client-runtime, web, and mobile typechecks passed.

UI evidence

Before: disabled environmentAfter: tap enables and reconnects
Red not-connected composer pill before activationConversation available after tapping the composer pill

The after screenshot was captured on an iOS Simulator against disposable state. Tapping the red composer status pill enabled the saved environment; the disconnected placeholder and pill disappeared, and the thread became available without leaving the conversation.

Latest review pass

The underlying activation runtime now survives transient startup reconciliation failures, serializes registration with startup, clears stale disabled state on re-pair/platform restoration, and initializes presentation from authoritative desired state. Cloud switches disable without deleting registrations, and editing a disabled bearer environment preserves its activation state. The composer intentionally remains a no-op when its route environment no longer exists.

Latest integrated verification: client-runtime 47 test files / 598 tests passed; mobile 100 test files / 622 tests passed; client-runtime, web, and mobile typechecks passed.

Final review pass

The dependent runtime now updates registrations atomically while preserving activation, avoids transient connections for disabled edits, serializes activation controls with Save, and presents disabled environments without stale failures. The composer intentionally remains a no-op when its route environment no longer exists.

Latest verification: client-runtime 47 test files / 599 tests passed; mobile 100 test files / 622 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed. The Fallow new-only audit gate passed.

Rebased onto upstream main at 5661c6116 on 2026-08-07. Post-rebase verification: client-runtime 47 test files / 603 tests passed; mobile 100 test files / 624 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed.

Model: GPT-5; harness: Codex.


Note

Medium Risk
Changes connection catalog persistence, registry startup/reconciliation, and supervisor desired-state behavior across mobile, web, and desktop; incorrect activation handling could leave environments disconnected or fail startup until retry.

Overview
Adds persistent enable/disable for saved environments via disabledEnvironmentIds in the connection catalog and a ConnectionActivationStore on mobile, web, and desktop. Toggling off disconnects without removing the registration; presentation and workspace models now expose enabled separately from connection phase.

Mobile & web UI wire activation through EnvironmentActivationSwitch / settings edit dialogs (including bearer label/URL updates on web). Cloud rows use enable + retry instead of connect/disconnect semantics, with disabled environments shown as "Disabled" without stale error UI.

Thread composer (mobile): the status pill calls setEnabled(true) when the route environment is disabled (threadEnvironmentActivationAction), and keeps retry when already enabled—fixing taps that previously no-op’d because the supervisor had desired: false.

Runtime: registry startup retries on init failure; bearer profile updates go through updateRegistration; Connectivity.followNetworkStatus refreshes status on app wake with revision-safe application. Pairing forms gain parsePairingFields for pasted full URLs on blur/submit.

Reviewed by Cursor Bugbot for commit 3708623. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Enable environment activation toggling from the composer and settings UI

  • Adds a disabledEnvironmentIds field to the connection catalog document and a new ConnectionActivationStore persistence service to list, set, and reconcile per-environment enabled state across web, mobile, and desktop.
  • Extends EnvironmentRegistry with setEnabled and updateRegistration APIs; toggling enabled state connects or disconnects the supervisor immediately and is persisted atomically under an activation lock.
  • Startup now reconciles persisted activation state against known environments and retries with exponential backoff on failure.
  • Adds UI controls on mobile (ConnectionEnvironmentRow, CloudEnvironmentRowShell, EnvironmentActivationSwitch) and web (ConnectionsSettings) to enable/disable environments; disabled environments show an 'Enable' button and suppress connection errors.
  • Replaces direct connectivity.changes subscriptions with followNetworkStatus, which serializes wakeup-driven refreshes and deduplicates redundant status applications in RelayEnvironmentDiscovery, EnvironmentSupervisor, and the registry.
  • Risk: start on EnvironmentRegistry can now fail with a ConnectionPersistenceError due to activation store operations; callers that previously assumed a non-failing start will need to handle this.

Macroscope summarized 3708623.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ccd4ff46-8269-43eb-94eb-0c0425948e15

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
@DominicVonkDominicVonk changed the title fix(mobile): enable environments from the composer[5/5] fix(mobile): enable environments from the composerAug 7, 2026
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk

Copy link
Copy Markdown
Author

Clean per-layer diff in the native fork stack: DominicVonk#5 (fork stack #6). This upstream draft remains the contribution discussion and review target.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 5c46076 to 3230b19CompareAugust 7, 2026 10:31

@macroscopeappmacroscopeappBot 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.

Effect service conventions review: one issue found. In apps/mobile/src/connection/storage.ts the ConnectionPersistenceErroroperation labels were shifted when the new activation operations were introduced, so each store now reports a failure under the wrong operation. The equivalent code in apps/web/src/connection/storage.ts labels these correctly, which makes the mobile mapping the outlier. Everything else (the new ConnectionActivationStore tag, the registry setEnabled operation, the new environment-catalog:set-enabled command, and the followNetworkStatus helper whose dependencies are still acquired via yield* in each caller's make) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3230b19 to e51b5eeCompareAugust 7, 2026 10:33
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e51b5ee to 1300026CompareAugust 7, 2026 10:43
Comment threadpackages/client-runtime/src/connection/connectivity.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 1300026 to 3693f9eCompareAugust 7, 2026 10:46
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3693f9e to 6519a5aCompareAugust 7, 2026 10:55
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 6519a5a to f5b6861CompareAugust 7, 2026 11:02
@DominicVonk
DominicVonk marked this pull request as ready for review August 7, 2026 11:08
Comment threadapps/mobile/src/state/use-remote-environment-registry.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces a new feature allowing users to enable/disable environments from the mobile composer and settings UI. New user-facing capabilities with new components and state management warrant human review. Additionally, open review comments identify bugs in the activation switch (pending state not cleared on success) and edit dialog (silently enables disabled environments).

You can customize Macroscope's approvability policy. Learn more.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from f5b6861 to b97a4c0CompareAugust 7, 2026 11:27
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 39c9900 to 0887a16CompareAugust 7, 2026 11:37
Comment threadpackages/client-runtime/src/connection/registry.ts
Comment threadapps/mobile/src/features/threads/ThreadRouteScreen.tsx
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 0887a16 to 61edeb4CompareAugust 7, 2026 11:44
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 61edeb4 to fa883a2CompareAugust 7, 2026 12:00
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
[environment.displayUrl, environment.label, isSaving],
);

const handleSave = useCallback(async () => {

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.

🟡 Mediumsettings/ConnectionsSettings.tsx:1437

handleSave calls onUpdate to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches EnvironmentRegistry.register, which unconditionally calls activation.setEnabled(environmentId, true) and installs the entry with initiallyDesired: true, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ConnectionsSettings.tsx around line 1437:
`handleSave` calls `onUpdate` to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches `EnvironmentRegistry.register`, which unconditionally calls `activation.setEnabled(environmentId, true)` and installs the entry with `initiallyDesired: true`, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

Comment threadapps/mobile/src/features/connection/CloudEnvironmentRows.tsx
Comment threadpackages/client-runtime/src/connection/layer.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch 2 times, most recently from 8acb832 to 274a5ccCompareAugust 7, 2026 12:09
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 274a5cc to def0a30CompareAugust 7, 2026 12:13

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit def0a301f7a5d453c3af54fef652b4100d2671a1. Configure here.

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated

@macroscopeappmacroscopeappBot 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.

Effect service conventions: one issue found — newly added Effect.catchTag usages in packages/client-runtime/src/connection/onboarding.ts should use Effect.catchTags({ ... }).

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from def0a30 to e909e9cCompareAugust 7, 2026 15:44
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e909e9c to cae5dbbCompareAugust 7, 2026 15:48
Comment threadpackages/client-runtime/src/relay/discovery.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from cae5dbb to 3708623CompareAugust 7, 2026 16:18
Comment on lines +27 to +30
const result = await props.onValueChange(enabled);
if (!AsyncResult.isSuccess(result)) {
setPending((current) => (current === request ? null : current));
}

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.

🟡 Mediumconnection/EnvironmentActivationSwitch.tsx:27

A successful toggle leaves pending set indefinitely, so if props.enabled later cycles back to the request's previous value, the switch re-enters a phantom pending state: isPending becomes true, the switch displays the stale requested value, and disables itself even though no request is in flight. The success path only clears pending on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

 const result = await props.onValueChange(enabled);
- if (!AsyncResult.isSuccess(result)) {+ if (AsyncResult.isSuccess(result)) {+ setPending((current) => (current === request ? null : current));+ } else {
setPending((current) => (current === request ? null : current));
}
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/features/connection/EnvironmentActivationSwitch.tsx around lines 27-30:
A successful toggle leaves `pending` set indefinitely, so if `props.enabled` later cycles back to the request's `previous` value, the switch re-enters a phantom pending state: `isPending` becomes `true`, the switch displays the stale `requested` value, and disables itself even though no request is in flight. The success path only clears `pending` on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

@DominicVonk

Copy link
Copy Markdown
Author

Superseded by #5598. The composer enable action now ships with the durable activation model and management UI in one independently mergeable PR based directly on main.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DominicVonk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[5/5] fix(mobile): enable environments from the composer - #5599

Closed
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable
Closed

[5/5] fix(mobile): enable environments from the composer#5599
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable

Conversation

@DominicVonk

@DominicVonkDominicVonk commented Aug 7, 2026

Copy link
Copy Markdown

Problem

The composer status pill is already tappable, but it always dispatches a retry. In the red environment is not connected state shown for an available environment, the supervisor's desired state is false. Retrying cannot activate that environment, so tapping the pill appears to do nothing.

Solution

Choose the action from the typed connection phase and authoritative activation state:

  • disabled environments dispatch setEnabled(environmentId, true);
  • enabled offline, connecting, reconnecting, connected-syncing, and error states keep the existing retry behavior;
  • a missing route environment remains a no-op.

Activation is projected from the supervisor's desired flag rather than inferred from transient connection phase. The decision remains isolated in a small typed helper, and activation still flows through the shared environment registry and supervisor.

User impact

Tapping the red status pill directly enables and reconnects a disabled environment for the open thread. Users no longer need to leave the conversation and find the environment toggle in Settings.

Stack

This PR is 5/5. Depends on layers 1–4, ending with 4/5, #5596.

Please review and merge the upstream PRs in order from 1 through 5. Because this repository does not have native stacked PRs enabled and cross-fork branches cannot be upstream base refs, the upstream diffs are cumulative. The corresponding fork PRs use the true dependent bases and provide the clean per-layer diffs.

LayerUpstream PRClean stacked diff
1#5597 — network-status recoveryfork #1
2#5600 — persistent environment activationfork #2
3#5598 — environment-management UIfork #3
4#5596 — pasted pairing-link parsingfork #4
5#5599 — composer-pill activationfork #5

Validation

apps/mobile
Test Files 1 passed (1)
Tests 2 passed (2)
tsc --noEmit: passed
Physical iPhone
Signed development app installed: passed
Application launch through devicectl: passed
Updated Metro bundle loaded: passed

The focused test verifies that a disabled environment enables while enabled connection states retry. Integrated stack validation after rebasing onto latest upstream main: 14 test files passed with 124 tests; client-runtime, web, and mobile typechecks passed.

UI evidence

Before: disabled environmentAfter: tap enables and reconnects
Red not-connected composer pill before activationConversation available after tapping the composer pill

The after screenshot was captured on an iOS Simulator against disposable state. Tapping the red composer status pill enabled the saved environment; the disconnected placeholder and pill disappeared, and the thread became available without leaving the conversation.

Latest review pass

The underlying activation runtime now survives transient startup reconciliation failures, serializes registration with startup, clears stale disabled state on re-pair/platform restoration, and initializes presentation from authoritative desired state. Cloud switches disable without deleting registrations, and editing a disabled bearer environment preserves its activation state. The composer intentionally remains a no-op when its route environment no longer exists.

Latest integrated verification: client-runtime 47 test files / 598 tests passed; mobile 100 test files / 622 tests passed; client-runtime, web, and mobile typechecks passed.

Final review pass

The dependent runtime now updates registrations atomically while preserving activation, avoids transient connections for disabled edits, serializes activation controls with Save, and presents disabled environments without stale failures. The composer intentionally remains a no-op when its route environment no longer exists.

Latest verification: client-runtime 47 test files / 599 tests passed; mobile 100 test files / 622 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed. The Fallow new-only audit gate passed.

Rebased onto upstream main at 5661c6116 on 2026-08-07. Post-rebase verification: client-runtime 47 test files / 603 tests passed; mobile 100 test files / 624 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed.

Model: GPT-5; harness: Codex.


Note

Medium Risk
Changes connection catalog persistence, registry startup/reconciliation, and supervisor desired-state behavior across mobile, web, and desktop; incorrect activation handling could leave environments disconnected or fail startup until retry.

Overview
Adds persistent enable/disable for saved environments via disabledEnvironmentIds in the connection catalog and a ConnectionActivationStore on mobile, web, and desktop. Toggling off disconnects without removing the registration; presentation and workspace models now expose enabled separately from connection phase.

Mobile & web UI wire activation through EnvironmentActivationSwitch / settings edit dialogs (including bearer label/URL updates on web). Cloud rows use enable + retry instead of connect/disconnect semantics, with disabled environments shown as "Disabled" without stale error UI.

Thread composer (mobile): the status pill calls setEnabled(true) when the route environment is disabled (threadEnvironmentActivationAction), and keeps retry when already enabled—fixing taps that previously no-op’d because the supervisor had desired: false.

Runtime: registry startup retries on init failure; bearer profile updates go through updateRegistration; Connectivity.followNetworkStatus refreshes status on app wake with revision-safe application. Pairing forms gain parsePairingFields for pasted full URLs on blur/submit.

Reviewed by Cursor Bugbot for commit 3708623. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Enable environment activation toggling from the composer and settings UI

  • Adds a disabledEnvironmentIds field to the connection catalog document and a new ConnectionActivationStore persistence service to list, set, and reconcile per-environment enabled state across web, mobile, and desktop.
  • Extends EnvironmentRegistry with setEnabled and updateRegistration APIs; toggling enabled state connects or disconnects the supervisor immediately and is persisted atomically under an activation lock.
  • Startup now reconciles persisted activation state against known environments and retries with exponential backoff on failure.
  • Adds UI controls on mobile (ConnectionEnvironmentRow, CloudEnvironmentRowShell, EnvironmentActivationSwitch) and web (ConnectionsSettings) to enable/disable environments; disabled environments show an 'Enable' button and suppress connection errors.
  • Replaces direct connectivity.changes subscriptions with followNetworkStatus, which serializes wakeup-driven refreshes and deduplicates redundant status applications in RelayEnvironmentDiscovery, EnvironmentSupervisor, and the registry.
  • Risk: start on EnvironmentRegistry can now fail with a ConnectionPersistenceError due to activation store operations; callers that previously assumed a non-failing start will need to handle this.

Macroscope summarized 3708623.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ccd4ff46-8269-43eb-94eb-0c0425948e15

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
@DominicVonkDominicVonk changed the title fix(mobile): enable environments from the composer[5/5] fix(mobile): enable environments from the composerAug 7, 2026
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk

Copy link
Copy Markdown
Author

Clean per-layer diff in the native fork stack: DominicVonk#5 (fork stack #6). This upstream draft remains the contribution discussion and review target.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 5c46076 to 3230b19CompareAugust 7, 2026 10:31

@macroscopeappmacroscopeappBot 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.

Effect service conventions review: one issue found. In apps/mobile/src/connection/storage.ts the ConnectionPersistenceErroroperation labels were shifted when the new activation operations were introduced, so each store now reports a failure under the wrong operation. The equivalent code in apps/web/src/connection/storage.ts labels these correctly, which makes the mobile mapping the outlier. Everything else (the new ConnectionActivationStore tag, the registry setEnabled operation, the new environment-catalog:set-enabled command, and the followNetworkStatus helper whose dependencies are still acquired via yield* in each caller's make) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3230b19 to e51b5eeCompareAugust 7, 2026 10:33
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e51b5ee to 1300026CompareAugust 7, 2026 10:43
Comment threadpackages/client-runtime/src/connection/connectivity.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 1300026 to 3693f9eCompareAugust 7, 2026 10:46
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3693f9e to 6519a5aCompareAugust 7, 2026 10:55
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 6519a5a to f5b6861CompareAugust 7, 2026 11:02
@DominicVonk
DominicVonk marked this pull request as ready for review August 7, 2026 11:08
Comment threadapps/mobile/src/state/use-remote-environment-registry.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces a new feature allowing users to enable/disable environments from the mobile composer and settings UI. New user-facing capabilities with new components and state management warrant human review. Additionally, open review comments identify bugs in the activation switch (pending state not cleared on success) and edit dialog (silently enables disabled environments).

You can customize Macroscope's approvability policy. Learn more.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from f5b6861 to b97a4c0CompareAugust 7, 2026 11:27
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 39c9900 to 0887a16CompareAugust 7, 2026 11:37
Comment threadpackages/client-runtime/src/connection/registry.ts
Comment threadapps/mobile/src/features/threads/ThreadRouteScreen.tsx
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 0887a16 to 61edeb4CompareAugust 7, 2026 11:44
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 61edeb4 to fa883a2CompareAugust 7, 2026 12:00
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
[environment.displayUrl, environment.label, isSaving],
);

const handleSave = useCallback(async () => {

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.

🟡 Mediumsettings/ConnectionsSettings.tsx:1437

handleSave calls onUpdate to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches EnvironmentRegistry.register, which unconditionally calls activation.setEnabled(environmentId, true) and installs the entry with initiallyDesired: true, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ConnectionsSettings.tsx around line 1437:
`handleSave` calls `onUpdate` to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches `EnvironmentRegistry.register`, which unconditionally calls `activation.setEnabled(environmentId, true)` and installs the entry with `initiallyDesired: true`, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

Comment threadapps/mobile/src/features/connection/CloudEnvironmentRows.tsx
Comment threadpackages/client-runtime/src/connection/layer.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch 2 times, most recently from 8acb832 to 274a5ccCompareAugust 7, 2026 12:09
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 274a5cc to def0a30CompareAugust 7, 2026 12:13

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit def0a301f7a5d453c3af54fef652b4100d2671a1. Configure here.

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated

@macroscopeappmacroscopeappBot 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.

Effect service conventions: one issue found — newly added Effect.catchTag usages in packages/client-runtime/src/connection/onboarding.ts should use Effect.catchTags({ ... }).

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from def0a30 to e909e9cCompareAugust 7, 2026 15:44
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e909e9c to cae5dbbCompareAugust 7, 2026 15:48
Comment threadpackages/client-runtime/src/relay/discovery.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from cae5dbb to 3708623CompareAugust 7, 2026 16:18
Comment on lines +27 to +30
const result = await props.onValueChange(enabled);
if (!AsyncResult.isSuccess(result)) {
setPending((current) => (current === request ? null : current));
}

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.

🟡 Mediumconnection/EnvironmentActivationSwitch.tsx:27

A successful toggle leaves pending set indefinitely, so if props.enabled later cycles back to the request's previous value, the switch re-enters a phantom pending state: isPending becomes true, the switch displays the stale requested value, and disables itself even though no request is in flight. The success path only clears pending on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

 const result = await props.onValueChange(enabled);
- if (!AsyncResult.isSuccess(result)) {+ if (AsyncResult.isSuccess(result)) {+ setPending((current) => (current === request ? null : current));+ } else {
setPending((current) => (current === request ? null : current));
}
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/features/connection/EnvironmentActivationSwitch.tsx around lines 27-30:
A successful toggle leaves `pending` set indefinitely, so if `props.enabled` later cycles back to the request's `previous` value, the switch re-enters a phantom pending state: `isPending` becomes `true`, the switch displays the stale `requested` value, and disables itself even though no request is in flight. The success path only clears `pending` on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

@DominicVonk

Copy link
Copy Markdown
Author

Superseded by #5598. The composer enable action now ships with the durable activation model and management UI in one independently mergeable PR based directly on main.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DominicVonk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[5/5] fix(mobile): enable environments from the composer - #5599

Closed
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable
Closed

[5/5] fix(mobile): enable environments from the composer#5599
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable

Conversation

@DominicVonk

@DominicVonkDominicVonk commented Aug 7, 2026

Copy link
Copy Markdown

Problem

The composer status pill is already tappable, but it always dispatches a retry. In the red environment is not connected state shown for an available environment, the supervisor's desired state is false. Retrying cannot activate that environment, so tapping the pill appears to do nothing.

Solution

Choose the action from the typed connection phase and authoritative activation state:

  • disabled environments dispatch setEnabled(environmentId, true);
  • enabled offline, connecting, reconnecting, connected-syncing, and error states keep the existing retry behavior;
  • a missing route environment remains a no-op.

Activation is projected from the supervisor's desired flag rather than inferred from transient connection phase. The decision remains isolated in a small typed helper, and activation still flows through the shared environment registry and supervisor.

User impact

Tapping the red status pill directly enables and reconnects a disabled environment for the open thread. Users no longer need to leave the conversation and find the environment toggle in Settings.

Stack

This PR is 5/5. Depends on layers 1–4, ending with 4/5, #5596.

Please review and merge the upstream PRs in order from 1 through 5. Because this repository does not have native stacked PRs enabled and cross-fork branches cannot be upstream base refs, the upstream diffs are cumulative. The corresponding fork PRs use the true dependent bases and provide the clean per-layer diffs.

LayerUpstream PRClean stacked diff
1#5597 — network-status recoveryfork #1
2#5600 — persistent environment activationfork #2
3#5598 — environment-management UIfork #3
4#5596 — pasted pairing-link parsingfork #4
5#5599 — composer-pill activationfork #5

Validation

apps/mobile
Test Files 1 passed (1)
Tests 2 passed (2)
tsc --noEmit: passed
Physical iPhone
Signed development app installed: passed
Application launch through devicectl: passed
Updated Metro bundle loaded: passed

The focused test verifies that a disabled environment enables while enabled connection states retry. Integrated stack validation after rebasing onto latest upstream main: 14 test files passed with 124 tests; client-runtime, web, and mobile typechecks passed.

UI evidence

Before: disabled environmentAfter: tap enables and reconnects
Red not-connected composer pill before activationConversation available after tapping the composer pill

The after screenshot was captured on an iOS Simulator against disposable state. Tapping the red composer status pill enabled the saved environment; the disconnected placeholder and pill disappeared, and the thread became available without leaving the conversation.

Latest review pass

The underlying activation runtime now survives transient startup reconciliation failures, serializes registration with startup, clears stale disabled state on re-pair/platform restoration, and initializes presentation from authoritative desired state. Cloud switches disable without deleting registrations, and editing a disabled bearer environment preserves its activation state. The composer intentionally remains a no-op when its route environment no longer exists.

Latest integrated verification: client-runtime 47 test files / 598 tests passed; mobile 100 test files / 622 tests passed; client-runtime, web, and mobile typechecks passed.

Final review pass

The dependent runtime now updates registrations atomically while preserving activation, avoids transient connections for disabled edits, serializes activation controls with Save, and presents disabled environments without stale failures. The composer intentionally remains a no-op when its route environment no longer exists.

Latest verification: client-runtime 47 test files / 599 tests passed; mobile 100 test files / 622 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed. The Fallow new-only audit gate passed.

Rebased onto upstream main at 5661c6116 on 2026-08-07. Post-rebase verification: client-runtime 47 test files / 603 tests passed; mobile 100 test files / 624 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed.

Model: GPT-5; harness: Codex.


Note

Medium Risk
Changes connection catalog persistence, registry startup/reconciliation, and supervisor desired-state behavior across mobile, web, and desktop; incorrect activation handling could leave environments disconnected or fail startup until retry.

Overview
Adds persistent enable/disable for saved environments via disabledEnvironmentIds in the connection catalog and a ConnectionActivationStore on mobile, web, and desktop. Toggling off disconnects without removing the registration; presentation and workspace models now expose enabled separately from connection phase.

Mobile & web UI wire activation through EnvironmentActivationSwitch / settings edit dialogs (including bearer label/URL updates on web). Cloud rows use enable + retry instead of connect/disconnect semantics, with disabled environments shown as "Disabled" without stale error UI.

Thread composer (mobile): the status pill calls setEnabled(true) when the route environment is disabled (threadEnvironmentActivationAction), and keeps retry when already enabled—fixing taps that previously no-op’d because the supervisor had desired: false.

Runtime: registry startup retries on init failure; bearer profile updates go through updateRegistration; Connectivity.followNetworkStatus refreshes status on app wake with revision-safe application. Pairing forms gain parsePairingFields for pasted full URLs on blur/submit.

Reviewed by Cursor Bugbot for commit 3708623. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Enable environment activation toggling from the composer and settings UI

  • Adds a disabledEnvironmentIds field to the connection catalog document and a new ConnectionActivationStore persistence service to list, set, and reconcile per-environment enabled state across web, mobile, and desktop.
  • Extends EnvironmentRegistry with setEnabled and updateRegistration APIs; toggling enabled state connects or disconnects the supervisor immediately and is persisted atomically under an activation lock.
  • Startup now reconciles persisted activation state against known environments and retries with exponential backoff on failure.
  • Adds UI controls on mobile (ConnectionEnvironmentRow, CloudEnvironmentRowShell, EnvironmentActivationSwitch) and web (ConnectionsSettings) to enable/disable environments; disabled environments show an 'Enable' button and suppress connection errors.
  • Replaces direct connectivity.changes subscriptions with followNetworkStatus, which serializes wakeup-driven refreshes and deduplicates redundant status applications in RelayEnvironmentDiscovery, EnvironmentSupervisor, and the registry.
  • Risk: start on EnvironmentRegistry can now fail with a ConnectionPersistenceError due to activation store operations; callers that previously assumed a non-failing start will need to handle this.

Macroscope summarized 3708623.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ccd4ff46-8269-43eb-94eb-0c0425948e15

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
@DominicVonkDominicVonk changed the title fix(mobile): enable environments from the composer[5/5] fix(mobile): enable environments from the composerAug 7, 2026
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk

Copy link
Copy Markdown
Author

Clean per-layer diff in the native fork stack: DominicVonk#5 (fork stack #6). This upstream draft remains the contribution discussion and review target.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 5c46076 to 3230b19CompareAugust 7, 2026 10:31

@macroscopeappmacroscopeappBot 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.

Effect service conventions review: one issue found. In apps/mobile/src/connection/storage.ts the ConnectionPersistenceErroroperation labels were shifted when the new activation operations were introduced, so each store now reports a failure under the wrong operation. The equivalent code in apps/web/src/connection/storage.ts labels these correctly, which makes the mobile mapping the outlier. Everything else (the new ConnectionActivationStore tag, the registry setEnabled operation, the new environment-catalog:set-enabled command, and the followNetworkStatus helper whose dependencies are still acquired via yield* in each caller's make) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3230b19 to e51b5eeCompareAugust 7, 2026 10:33
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e51b5ee to 1300026CompareAugust 7, 2026 10:43
Comment threadpackages/client-runtime/src/connection/connectivity.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 1300026 to 3693f9eCompareAugust 7, 2026 10:46
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3693f9e to 6519a5aCompareAugust 7, 2026 10:55
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 6519a5a to f5b6861CompareAugust 7, 2026 11:02
@DominicVonk
DominicVonk marked this pull request as ready for review August 7, 2026 11:08
Comment threadapps/mobile/src/state/use-remote-environment-registry.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces a new feature allowing users to enable/disable environments from the mobile composer and settings UI. New user-facing capabilities with new components and state management warrant human review. Additionally, open review comments identify bugs in the activation switch (pending state not cleared on success) and edit dialog (silently enables disabled environments).

You can customize Macroscope's approvability policy. Learn more.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from f5b6861 to b97a4c0CompareAugust 7, 2026 11:27
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 39c9900 to 0887a16CompareAugust 7, 2026 11:37
Comment threadpackages/client-runtime/src/connection/registry.ts
Comment threadapps/mobile/src/features/threads/ThreadRouteScreen.tsx
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 0887a16 to 61edeb4CompareAugust 7, 2026 11:44
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 61edeb4 to fa883a2CompareAugust 7, 2026 12:00
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
[environment.displayUrl, environment.label, isSaving],
);

const handleSave = useCallback(async () => {

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.

🟡 Mediumsettings/ConnectionsSettings.tsx:1437

handleSave calls onUpdate to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches EnvironmentRegistry.register, which unconditionally calls activation.setEnabled(environmentId, true) and installs the entry with initiallyDesired: true, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ConnectionsSettings.tsx around line 1437:
`handleSave` calls `onUpdate` to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches `EnvironmentRegistry.register`, which unconditionally calls `activation.setEnabled(environmentId, true)` and installs the entry with `initiallyDesired: true`, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

Comment threadapps/mobile/src/features/connection/CloudEnvironmentRows.tsx
Comment threadpackages/client-runtime/src/connection/layer.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch 2 times, most recently from 8acb832 to 274a5ccCompareAugust 7, 2026 12:09
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 274a5cc to def0a30CompareAugust 7, 2026 12:13

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit def0a301f7a5d453c3af54fef652b4100d2671a1. Configure here.

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated

@macroscopeappmacroscopeappBot 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.

Effect service conventions: one issue found — newly added Effect.catchTag usages in packages/client-runtime/src/connection/onboarding.ts should use Effect.catchTags({ ... }).

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from def0a30 to e909e9cCompareAugust 7, 2026 15:44
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e909e9c to cae5dbbCompareAugust 7, 2026 15:48
Comment threadpackages/client-runtime/src/relay/discovery.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from cae5dbb to 3708623CompareAugust 7, 2026 16:18
Comment on lines +27 to +30
const result = await props.onValueChange(enabled);
if (!AsyncResult.isSuccess(result)) {
setPending((current) => (current === request ? null : current));
}

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.

🟡 Mediumconnection/EnvironmentActivationSwitch.tsx:27

A successful toggle leaves pending set indefinitely, so if props.enabled later cycles back to the request's previous value, the switch re-enters a phantom pending state: isPending becomes true, the switch displays the stale requested value, and disables itself even though no request is in flight. The success path only clears pending on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

 const result = await props.onValueChange(enabled);
- if (!AsyncResult.isSuccess(result)) {+ if (AsyncResult.isSuccess(result)) {+ setPending((current) => (current === request ? null : current));+ } else {
setPending((current) => (current === request ? null : current));
}
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/features/connection/EnvironmentActivationSwitch.tsx around lines 27-30:
A successful toggle leaves `pending` set indefinitely, so if `props.enabled` later cycles back to the request's `previous` value, the switch re-enters a phantom pending state: `isPending` becomes `true`, the switch displays the stale `requested` value, and disables itself even though no request is in flight. The success path only clears `pending` on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

@DominicVonk

Copy link
Copy Markdown
Author

Superseded by #5598. The composer enable action now ships with the durable activation model and management UI in one independently mergeable PR based directly on main.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DominicVonk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[5/5] fix(mobile): enable environments from the composer - #5599

Closed
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable
Closed

[5/5] fix(mobile): enable environments from the composer#5599
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable

Conversation

@DominicVonk

@DominicVonkDominicVonk commented Aug 7, 2026

Copy link
Copy Markdown

Problem

The composer status pill is already tappable, but it always dispatches a retry. In the red environment is not connected state shown for an available environment, the supervisor's desired state is false. Retrying cannot activate that environment, so tapping the pill appears to do nothing.

Solution

Choose the action from the typed connection phase and authoritative activation state:

  • disabled environments dispatch setEnabled(environmentId, true);
  • enabled offline, connecting, reconnecting, connected-syncing, and error states keep the existing retry behavior;
  • a missing route environment remains a no-op.

Activation is projected from the supervisor's desired flag rather than inferred from transient connection phase. The decision remains isolated in a small typed helper, and activation still flows through the shared environment registry and supervisor.

User impact

Tapping the red status pill directly enables and reconnects a disabled environment for the open thread. Users no longer need to leave the conversation and find the environment toggle in Settings.

Stack

This PR is 5/5. Depends on layers 1–4, ending with 4/5, #5596.

Please review and merge the upstream PRs in order from 1 through 5. Because this repository does not have native stacked PRs enabled and cross-fork branches cannot be upstream base refs, the upstream diffs are cumulative. The corresponding fork PRs use the true dependent bases and provide the clean per-layer diffs.

LayerUpstream PRClean stacked diff
1#5597 — network-status recoveryfork #1
2#5600 — persistent environment activationfork #2
3#5598 — environment-management UIfork #3
4#5596 — pasted pairing-link parsingfork #4
5#5599 — composer-pill activationfork #5

Validation

apps/mobile
Test Files 1 passed (1)
Tests 2 passed (2)
tsc --noEmit: passed
Physical iPhone
Signed development app installed: passed
Application launch through devicectl: passed
Updated Metro bundle loaded: passed

The focused test verifies that a disabled environment enables while enabled connection states retry. Integrated stack validation after rebasing onto latest upstream main: 14 test files passed with 124 tests; client-runtime, web, and mobile typechecks passed.

UI evidence

Before: disabled environmentAfter: tap enables and reconnects
Red not-connected composer pill before activationConversation available after tapping the composer pill

The after screenshot was captured on an iOS Simulator against disposable state. Tapping the red composer status pill enabled the saved environment; the disconnected placeholder and pill disappeared, and the thread became available without leaving the conversation.

Latest review pass

The underlying activation runtime now survives transient startup reconciliation failures, serializes registration with startup, clears stale disabled state on re-pair/platform restoration, and initializes presentation from authoritative desired state. Cloud switches disable without deleting registrations, and editing a disabled bearer environment preserves its activation state. The composer intentionally remains a no-op when its route environment no longer exists.

Latest integrated verification: client-runtime 47 test files / 598 tests passed; mobile 100 test files / 622 tests passed; client-runtime, web, and mobile typechecks passed.

Final review pass

The dependent runtime now updates registrations atomically while preserving activation, avoids transient connections for disabled edits, serializes activation controls with Save, and presents disabled environments without stale failures. The composer intentionally remains a no-op when its route environment no longer exists.

Latest verification: client-runtime 47 test files / 599 tests passed; mobile 100 test files / 622 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed. The Fallow new-only audit gate passed.

Rebased onto upstream main at 5661c6116 on 2026-08-07. Post-rebase verification: client-runtime 47 test files / 603 tests passed; mobile 100 test files / 624 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed.

Model: GPT-5; harness: Codex.


Note

Medium Risk
Changes connection catalog persistence, registry startup/reconciliation, and supervisor desired-state behavior across mobile, web, and desktop; incorrect activation handling could leave environments disconnected or fail startup until retry.

Overview
Adds persistent enable/disable for saved environments via disabledEnvironmentIds in the connection catalog and a ConnectionActivationStore on mobile, web, and desktop. Toggling off disconnects without removing the registration; presentation and workspace models now expose enabled separately from connection phase.

Mobile & web UI wire activation through EnvironmentActivationSwitch / settings edit dialogs (including bearer label/URL updates on web). Cloud rows use enable + retry instead of connect/disconnect semantics, with disabled environments shown as "Disabled" without stale error UI.

Thread composer (mobile): the status pill calls setEnabled(true) when the route environment is disabled (threadEnvironmentActivationAction), and keeps retry when already enabled—fixing taps that previously no-op’d because the supervisor had desired: false.

Runtime: registry startup retries on init failure; bearer profile updates go through updateRegistration; Connectivity.followNetworkStatus refreshes status on app wake with revision-safe application. Pairing forms gain parsePairingFields for pasted full URLs on blur/submit.

Reviewed by Cursor Bugbot for commit 3708623. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Enable environment activation toggling from the composer and settings UI

  • Adds a disabledEnvironmentIds field to the connection catalog document and a new ConnectionActivationStore persistence service to list, set, and reconcile per-environment enabled state across web, mobile, and desktop.
  • Extends EnvironmentRegistry with setEnabled and updateRegistration APIs; toggling enabled state connects or disconnects the supervisor immediately and is persisted atomically under an activation lock.
  • Startup now reconciles persisted activation state against known environments and retries with exponential backoff on failure.
  • Adds UI controls on mobile (ConnectionEnvironmentRow, CloudEnvironmentRowShell, EnvironmentActivationSwitch) and web (ConnectionsSettings) to enable/disable environments; disabled environments show an 'Enable' button and suppress connection errors.
  • Replaces direct connectivity.changes subscriptions with followNetworkStatus, which serializes wakeup-driven refreshes and deduplicates redundant status applications in RelayEnvironmentDiscovery, EnvironmentSupervisor, and the registry.
  • Risk: start on EnvironmentRegistry can now fail with a ConnectionPersistenceError due to activation store operations; callers that previously assumed a non-failing start will need to handle this.

Macroscope summarized 3708623.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ccd4ff46-8269-43eb-94eb-0c0425948e15

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
@DominicVonkDominicVonk changed the title fix(mobile): enable environments from the composer[5/5] fix(mobile): enable environments from the composerAug 7, 2026
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk

Copy link
Copy Markdown
Author

Clean per-layer diff in the native fork stack: DominicVonk#5 (fork stack #6). This upstream draft remains the contribution discussion and review target.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 5c46076 to 3230b19CompareAugust 7, 2026 10:31

@macroscopeappmacroscopeappBot 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.

Effect service conventions review: one issue found. In apps/mobile/src/connection/storage.ts the ConnectionPersistenceErroroperation labels were shifted when the new activation operations were introduced, so each store now reports a failure under the wrong operation. The equivalent code in apps/web/src/connection/storage.ts labels these correctly, which makes the mobile mapping the outlier. Everything else (the new ConnectionActivationStore tag, the registry setEnabled operation, the new environment-catalog:set-enabled command, and the followNetworkStatus helper whose dependencies are still acquired via yield* in each caller's make) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3230b19 to e51b5eeCompareAugust 7, 2026 10:33
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e51b5ee to 1300026CompareAugust 7, 2026 10:43
Comment threadpackages/client-runtime/src/connection/connectivity.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 1300026 to 3693f9eCompareAugust 7, 2026 10:46
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3693f9e to 6519a5aCompareAugust 7, 2026 10:55
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 6519a5a to f5b6861CompareAugust 7, 2026 11:02
@DominicVonk
DominicVonk marked this pull request as ready for review August 7, 2026 11:08
Comment threadapps/mobile/src/state/use-remote-environment-registry.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces a new feature allowing users to enable/disable environments from the mobile composer and settings UI. New user-facing capabilities with new components and state management warrant human review. Additionally, open review comments identify bugs in the activation switch (pending state not cleared on success) and edit dialog (silently enables disabled environments).

You can customize Macroscope's approvability policy. Learn more.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from f5b6861 to b97a4c0CompareAugust 7, 2026 11:27
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 39c9900 to 0887a16CompareAugust 7, 2026 11:37
Comment threadpackages/client-runtime/src/connection/registry.ts
Comment threadapps/mobile/src/features/threads/ThreadRouteScreen.tsx
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 0887a16 to 61edeb4CompareAugust 7, 2026 11:44
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 61edeb4 to fa883a2CompareAugust 7, 2026 12:00
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
[environment.displayUrl, environment.label, isSaving],
);

const handleSave = useCallback(async () => {

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.

🟡 Mediumsettings/ConnectionsSettings.tsx:1437

handleSave calls onUpdate to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches EnvironmentRegistry.register, which unconditionally calls activation.setEnabled(environmentId, true) and installs the entry with initiallyDesired: true, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ConnectionsSettings.tsx around line 1437:
`handleSave` calls `onUpdate` to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches `EnvironmentRegistry.register`, which unconditionally calls `activation.setEnabled(environmentId, true)` and installs the entry with `initiallyDesired: true`, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

Comment threadapps/mobile/src/features/connection/CloudEnvironmentRows.tsx
Comment threadpackages/client-runtime/src/connection/layer.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch 2 times, most recently from 8acb832 to 274a5ccCompareAugust 7, 2026 12:09
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 274a5cc to def0a30CompareAugust 7, 2026 12:13

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit def0a301f7a5d453c3af54fef652b4100d2671a1. Configure here.

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated

@macroscopeappmacroscopeappBot 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.

Effect service conventions: one issue found — newly added Effect.catchTag usages in packages/client-runtime/src/connection/onboarding.ts should use Effect.catchTags({ ... }).

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from def0a30 to e909e9cCompareAugust 7, 2026 15:44
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e909e9c to cae5dbbCompareAugust 7, 2026 15:48
Comment threadpackages/client-runtime/src/relay/discovery.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from cae5dbb to 3708623CompareAugust 7, 2026 16:18
Comment on lines +27 to +30
const result = await props.onValueChange(enabled);
if (!AsyncResult.isSuccess(result)) {
setPending((current) => (current === request ? null : current));
}

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.

🟡 Mediumconnection/EnvironmentActivationSwitch.tsx:27

A successful toggle leaves pending set indefinitely, so if props.enabled later cycles back to the request's previous value, the switch re-enters a phantom pending state: isPending becomes true, the switch displays the stale requested value, and disables itself even though no request is in flight. The success path only clears pending on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

 const result = await props.onValueChange(enabled);
- if (!AsyncResult.isSuccess(result)) {+ if (AsyncResult.isSuccess(result)) {+ setPending((current) => (current === request ? null : current));+ } else {
setPending((current) => (current === request ? null : current));
}
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/features/connection/EnvironmentActivationSwitch.tsx around lines 27-30:
A successful toggle leaves `pending` set indefinitely, so if `props.enabled` later cycles back to the request's `previous` value, the switch re-enters a phantom pending state: `isPending` becomes `true`, the switch displays the stale `requested` value, and disables itself even though no request is in flight. The success path only clears `pending` on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

@DominicVonk

Copy link
Copy Markdown
Author

Superseded by #5598. The composer enable action now ships with the durable activation model and management UI in one independently mergeable PR based directly on main.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DominicVonk
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[5/5] fix(mobile): enable environments from the composer - #5599

Closed
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable
Closed

[5/5] fix(mobile): enable environments from the composer#5599
DominicVonk wants to merge 7 commits into
pingdotgg:mainfrom
DominicVonk:codex/mobile-composer-enable

Conversation

@DominicVonk

@DominicVonkDominicVonk commented Aug 7, 2026

Copy link
Copy Markdown

Problem

The composer status pill is already tappable, but it always dispatches a retry. In the red environment is not connected state shown for an available environment, the supervisor's desired state is false. Retrying cannot activate that environment, so tapping the pill appears to do nothing.

Solution

Choose the action from the typed connection phase and authoritative activation state:

  • disabled environments dispatch setEnabled(environmentId, true);
  • enabled offline, connecting, reconnecting, connected-syncing, and error states keep the existing retry behavior;
  • a missing route environment remains a no-op.

Activation is projected from the supervisor's desired flag rather than inferred from transient connection phase. The decision remains isolated in a small typed helper, and activation still flows through the shared environment registry and supervisor.

User impact

Tapping the red status pill directly enables and reconnects a disabled environment for the open thread. Users no longer need to leave the conversation and find the environment toggle in Settings.

Stack

This PR is 5/5. Depends on layers 1–4, ending with 4/5, #5596.

Please review and merge the upstream PRs in order from 1 through 5. Because this repository does not have native stacked PRs enabled and cross-fork branches cannot be upstream base refs, the upstream diffs are cumulative. The corresponding fork PRs use the true dependent bases and provide the clean per-layer diffs.

LayerUpstream PRClean stacked diff
1#5597 — network-status recoveryfork #1
2#5600 — persistent environment activationfork #2
3#5598 — environment-management UIfork #3
4#5596 — pasted pairing-link parsingfork #4
5#5599 — composer-pill activationfork #5

Validation

apps/mobile
Test Files 1 passed (1)
Tests 2 passed (2)
tsc --noEmit: passed
Physical iPhone
Signed development app installed: passed
Application launch through devicectl: passed
Updated Metro bundle loaded: passed

The focused test verifies that a disabled environment enables while enabled connection states retry. Integrated stack validation after rebasing onto latest upstream main: 14 test files passed with 124 tests; client-runtime, web, and mobile typechecks passed.

UI evidence

Before: disabled environmentAfter: tap enables and reconnects
Red not-connected composer pill before activationConversation available after tapping the composer pill

The after screenshot was captured on an iOS Simulator against disposable state. Tapping the red composer status pill enabled the saved environment; the disconnected placeholder and pill disappeared, and the thread became available without leaving the conversation.

Latest review pass

The underlying activation runtime now survives transient startup reconciliation failures, serializes registration with startup, clears stale disabled state on re-pair/platform restoration, and initializes presentation from authoritative desired state. Cloud switches disable without deleting registrations, and editing a disabled bearer environment preserves its activation state. The composer intentionally remains a no-op when its route environment no longer exists.

Latest integrated verification: client-runtime 47 test files / 598 tests passed; mobile 100 test files / 622 tests passed; client-runtime, web, and mobile typechecks passed.

Final review pass

The dependent runtime now updates registrations atomically while preserving activation, avoids transient connections for disabled edits, serializes activation controls with Save, and presents disabled environments without stale failures. The composer intentionally remains a no-op when its route environment no longer exists.

Latest verification: client-runtime 47 test files / 599 tests passed; mobile 100 test files / 622 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed. The Fallow new-only audit gate passed.

Rebased onto upstream main at 5661c6116 on 2026-08-07. Post-rebase verification: client-runtime 47 test files / 603 tests passed; mobile 100 test files / 624 tests passed; desktop 58 test files / 447 tests passed; client-runtime, web, mobile, and desktop typechecks passed.

Model: GPT-5; harness: Codex.


Note

Medium Risk
Changes connection catalog persistence, registry startup/reconciliation, and supervisor desired-state behavior across mobile, web, and desktop; incorrect activation handling could leave environments disconnected or fail startup until retry.

Overview
Adds persistent enable/disable for saved environments via disabledEnvironmentIds in the connection catalog and a ConnectionActivationStore on mobile, web, and desktop. Toggling off disconnects without removing the registration; presentation and workspace models now expose enabled separately from connection phase.

Mobile & web UI wire activation through EnvironmentActivationSwitch / settings edit dialogs (including bearer label/URL updates on web). Cloud rows use enable + retry instead of connect/disconnect semantics, with disabled environments shown as "Disabled" without stale error UI.

Thread composer (mobile): the status pill calls setEnabled(true) when the route environment is disabled (threadEnvironmentActivationAction), and keeps retry when already enabled—fixing taps that previously no-op’d because the supervisor had desired: false.

Runtime: registry startup retries on init failure; bearer profile updates go through updateRegistration; Connectivity.followNetworkStatus refreshes status on app wake with revision-safe application. Pairing forms gain parsePairingFields for pasted full URLs on blur/submit.

Reviewed by Cursor Bugbot for commit 3708623. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Enable environment activation toggling from the composer and settings UI

  • Adds a disabledEnvironmentIds field to the connection catalog document and a new ConnectionActivationStore persistence service to list, set, and reconcile per-environment enabled state across web, mobile, and desktop.
  • Extends EnvironmentRegistry with setEnabled and updateRegistration APIs; toggling enabled state connects or disconnects the supervisor immediately and is persisted atomically under an activation lock.
  • Startup now reconciles persisted activation state against known environments and retries with exponential backoff on failure.
  • Adds UI controls on mobile (ConnectionEnvironmentRow, CloudEnvironmentRowShell, EnvironmentActivationSwitch) and web (ConnectionsSettings) to enable/disable environments; disabled environments show an 'Enable' button and suppress connection errors.
  • Replaces direct connectivity.changes subscriptions with followNetworkStatus, which serializes wakeup-driven refreshes and deduplicates redundant status applications in RelayEnvironmentDiscovery, EnvironmentSupervisor, and the registry.
  • Risk: start on EnvironmentRegistry can now fail with a ConnectionPersistenceError due to activation store operations; callers that previously assumed a non-failing start will need to handle this.

Macroscope summarized 3708623.

@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ccd4ff46-8269-43eb-94eb-0c0425948e15

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
@DominicVonkDominicVonk changed the title fix(mobile): enable environments from the composer[5/5] fix(mobile): enable environments from the composerAug 7, 2026
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk

Copy link
Copy Markdown
Author

Clean per-layer diff in the native fork stack: DominicVonk#5 (fork stack #6). This upstream draft remains the contribution discussion and review target.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 5c46076 to 3230b19CompareAugust 7, 2026 10:31

@macroscopeappmacroscopeappBot 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.

Effect service conventions review: one issue found. In apps/mobile/src/connection/storage.ts the ConnectionPersistenceErroroperation labels were shifted when the new activation operations were introduced, so each store now reports a failure under the wrong operation. The equivalent code in apps/web/src/connection/storage.ts labels these correctly, which makes the mobile mapping the outlier. Everything else (the new ConnectionActivationStore tag, the registry setEnabled operation, the new environment-catalog:set-enabled command, and the followNetworkStatus helper whose dependencies are still acquired via yield* in each caller's make) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts Outdated
Comment threadapps/mobile/src/connection/storage.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3230b19 to e51b5eeCompareAugust 7, 2026 10:33
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e51b5ee to 1300026CompareAugust 7, 2026 10:43
Comment threadpackages/client-runtime/src/connection/connectivity.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 1300026 to 3693f9eCompareAugust 7, 2026 10:46
Comment threadpackages/client-runtime/src/connection/registry.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 3693f9e to 6519a5aCompareAugust 7, 2026 10:55
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 6519a5a to f5b6861CompareAugust 7, 2026 11:02
@DominicVonk
DominicVonk marked this pull request as ready for review August 7, 2026 11:08
Comment threadapps/mobile/src/state/use-remote-environment-registry.ts Outdated
@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces a new feature allowing users to enable/disable environments from the mobile composer and settings UI. New user-facing capabilities with new components and state management warrant human review. Additionally, open review comments identify bugs in the activation switch (pending state not cleared on success) and edit dialog (silently enables disabled environments).

You can customize Macroscope's approvability policy. Learn more.

@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from f5b6861 to b97a4c0CompareAugust 7, 2026 11:27
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 39c9900 to 0887a16CompareAugust 7, 2026 11:37
Comment threadpackages/client-runtime/src/connection/registry.ts
Comment threadapps/mobile/src/features/threads/ThreadRouteScreen.tsx
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 0887a16 to 61edeb4CompareAugust 7, 2026 11:44
Comment threadpackages/client-runtime/src/connection/registry.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 61edeb4 to fa883a2CompareAugust 7, 2026 12:00
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
[environment.displayUrl, environment.label, isSaving],
);

const handleSave = useCallback(async () => {

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.

🟡 Mediumsettings/ConnectionsSettings.tsx:1437

handleSave calls onUpdate to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches EnvironmentRegistry.register, which unconditionally calls activation.setEnabled(environmentId, true) and installs the entry with initiallyDesired: true, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/ConnectionsSettings.tsx around line 1437:
`handleSave` calls `onUpdate` to update the label or URL of a disabled environment, which causes the environment to become enabled and start connecting. When the edit dialog is open on a disabled bearer environment with the Enabled switch left off, saving the form silently enables it and triggers a connection. The underlying update path reaches `EnvironmentRegistry.register`, which unconditionally calls `activation.setEnabled(environmentId, true)` and installs the entry with `initiallyDesired: true`, so any edit is treated as a new enabled registration instead of preserving the existing activation state. The update path should preserve the environment's current enabled state rather than forcing it on.

Comment threadapps/mobile/src/features/connection/CloudEnvironmentRows.tsx
Comment threadpackages/client-runtime/src/connection/layer.ts
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch 2 times, most recently from 8acb832 to 274a5ccCompareAugust 7, 2026 12:09
Comment threadapps/web/src/components/settings/ConnectionsSettings.tsx
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from 274a5cc to def0a30CompareAugust 7, 2026 12:13

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit def0a301f7a5d453c3af54fef652b4100d2671a1. Configure here.

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated

@macroscopeappmacroscopeappBot 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.

Effect service conventions: one issue found — newly added Effect.catchTag usages in packages/client-runtime/src/connection/onboarding.ts should use Effect.catchTags({ ... }).

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
Comment threadpackages/client-runtime/src/connection/onboarding.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from def0a30 to e909e9cCompareAugust 7, 2026 15:44
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from e909e9c to cae5dbbCompareAugust 7, 2026 15:48
Comment threadpackages/client-runtime/src/relay/discovery.ts Outdated
@DominicVonk
DominicVonkforce-pushed the codex/mobile-composer-enable branch from cae5dbb to 3708623CompareAugust 7, 2026 16:18
Comment on lines +27 to +30
const result = await props.onValueChange(enabled);
if (!AsyncResult.isSuccess(result)) {
setPending((current) => (current === request ? null : current));
}

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.

🟡 Mediumconnection/EnvironmentActivationSwitch.tsx:27

A successful toggle leaves pending set indefinitely, so if props.enabled later cycles back to the request's previous value, the switch re-enters a phantom pending state: isPending becomes true, the switch displays the stale requested value, and disables itself even though no request is in flight. The success path only clears pending on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

 const result = await props.onValueChange(enabled);
- if (!AsyncResult.isSuccess(result)) {+ if (AsyncResult.isSuccess(result)) {+ setPending((current) => (current === request ? null : current));+ } else {
setPending((current) => (current === request ? null : current));
}
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/mobile/src/features/connection/EnvironmentActivationSwitch.tsx around lines 27-30:
A successful toggle leaves `pending` set indefinitely, so if `props.enabled` later cycles back to the request's `previous` value, the switch re-enters a phantom pending state: `isPending` becomes `true`, the switch displays the stale `requested` value, and disables itself even though no request is in flight. The success path only clears `pending` on failure, never on success. Clear the matching request after success as well, while still guarding against replacing a newer request.

@DominicVonk

Copy link
Copy Markdown
Author

Superseded by #5598. The composer enable action now ships with the durable activation model and management UI in one independently mergeable PR based directly on main.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DominicVonk