Skip to content

fix(codex): recover incomplete account deletion cleanup - #1324

Closed
chrisae9 wants to merge 1 commit into
lidge-jun:devfrom
chrisae9:agent/codex-account-delete-recovery
Closed

fix(codex): recover incomplete account deletion cleanup#1324
chrisae9 wants to merge 1 commit into
lidge-jun:devfrom
chrisae9:agent/codex-account-delete-recovery

Conversation

@chrisae9

@chrisae9 chrisae9 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

This is the focused recovery follow-up to the non-blocking account-deletion note in Wibias's review of #1303. #1319 made account removal durable before destructive cleanup; this PR makes the remaining post-commit cleanup failure explicit and safely recoverable.

  • Return a successful deletion with accountCleanupPending: true when the account row is gone but local credential cleanup did not finish.
  • Add a cleanup-only retry through DELETE ...?cleanupOnly=1, ocx account remove ... --cleanup-only, and the dashboard.
  • Require authoritative persisted configuration and live state to agree that the account remains absent before cleanup-only can touch credentials. Ambiguous or re-added accounts fail closed with HTTP 409.
  • Invalidate runtime ownership before reporting pending cleanup and converge picker/catalog state independently.
  • Acquire the commit-required SQLite lock before external config or credential writes, preventing a rollback-journal reader from blocking COMMIT after those writes complete.
  • Document the recovery response and workflow across the supported locales.

Dashboard recovery state

Dashboard showing the pending account-cleanup notice and Retry cleanup action

The screenshot uses synthetic .invalid account data. The opaque account ID needed for retry remains component-owned and is never displayed in the recovery notice.

Verification

  • bun run prepush — 10,153 pass / 10 skip / 0 fail; typecheck, changed-dashboard lint, privacy scan, and React Doctor passed.
  • bun test tests/codex-account-delete-atomicity.test.ts tests/codex-auth-api.test.ts tests/cli-account.test.ts — passed.
  • cd gui && bun test tests/codex-account-pool-behaviour.test.tsx tests/codex-account-pool-toast-tone.test.tsx tests/codex-account-pool-pinned-badge.test.tsx — passed.
  • Documentation site build — passed.
  • Root and dashboard dependency audits — passed.
  • git diff --check upstream/dev...HEAD — clean.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • New Features
    • Added --cleanup-only to retry incomplete Codex account credential cleanup.
    • CLI, API, and dashboard now show pending cleanup status and provide retry actions.
  • Bug Fixes
    • Account deletion and retries are idempotent and block unsafe cleanup when account presence is uncertain.
    • Improved handling of missing and orphaned account credentials.
  • Documentation
    • Updated CLI and management API guidance across supported languages.
  • Localization
    • Added cleanup status and retry messages in multiple languages.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ea50920f-df7a-436d-ada7-6df8e4be6368

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

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Codex account deletion now supports deferred credential cleanup and cleanup-only retries. The API, CLI, and GUI report pending cleanup, prevent unsafe retries when an account exists, and provide retry feedback. SQLite mutation locking now uses exclusive transactions.

Changes

Codex account cleanup lifecycle

Layer / File(s) Summary
Lifecycle deletion and mutation locking
src/codex/account-lifecycle.ts, src/config.ts, tests/codex-account-delete-atomicity.test.ts, tests/config-mutation-lock.test.ts
Deletion classifies persisted account state, supports cleanup-only retries, restores configuration after failed persistence, and performs cleanup outside the mutation body. Mutation locking uses BEGIN EXCLUSIVE.
Management API deletion contract
src/codex/auth-api.ts, structure/05_gui-and-management-api.md, docs-site/src/content/docs/*/reference/management-api.md, tests/codex-auth-api.test.ts
The DELETE endpoint supports cleanupOnly=1, returns accountCleanupPending after cleanup failure, returns 409 for unsafe retries, and preserves idempotent cleanup behavior.
CLI cleanup-only workflow
src/cli/account*.ts, tests/cli-account.test.ts, docs-site/src/content/docs/*/reference/cli/providers-accounts.md
ocx account remove accepts --cleanup-only for Codex accounts, sends retryable DELETE requests, and reports pending or completed cleanup.
GUI cleanup feedback and retry
gui/src/codex-account-mutation.ts, gui/src/hooks/useCodexAccountPool.ts, gui/src/components/CodexAccountPool.tsx, gui/src/components/codex-account-pool-main-card.tsx, gui/src/i18n/*.ts, gui/tests/*
The GUI displays persistent pending-cleanup feedback, exposes a retry action, handles account-present conflicts, and adds localized status messages and tests.

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

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant GUI
  participant ManagementAPI
  participant AccountLifecycle
  participant CredentialStore
  User->>GUI: Remove Codex account
  GUI->>ManagementAPI: DELETE account
  ManagementAPI->>AccountLifecycle: Delete ownership and invalidate runtime state
  AccountLifecycle->>CredentialStore: Remove local credentials
  CredentialStore-->>ManagementAPI: Return cleanup result
  ManagementAPI-->>GUI: Return completion or accountCleanupPending
  GUI->>ManagementAPI: Retry with cleanupOnly=1
  ManagementAPI->>AccountLifecycle: Validate persisted account absence
  AccountLifecycle->>CredentialStore: Remove remaining credentials
  CredentialStore-->>GUI: Return cleanup completion
Loading

Possibly related PRs

Suggested labels: maintainer-sponsored

Suggested reviewers: ingwannu, lidge-jun, wibias

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes recovery of incomplete Codex account-deletion cleanup, which is the primary change.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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-actions github-actions Bot added the bug Something isn't working label Aug 9, 2026
@chrisae9

chrisae9 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs-site/src/content/docs/reference/cli/providers-accounts.md`:
- Around line 236-260: Update the provider-specific deletion help excerpts to
distinguish OAuth/API-key existence validation from Codex DELETE behavior for
absent accounts, and include --cleanup-only where the excerpt is complete. Apply
the same correction to
docs-site/src/content/docs/reference/cli/providers-accounts.md lines 236-260,
docs-site/src/content/docs/ja/reference/cli/providers-accounts.md lines 185-200,
docs-site/src/content/docs/ko/reference/cli/providers-accounts.md lines 184-199,
docs-site/src/content/docs/ru/reference/cli/providers-accounts.md lines 233-258,
and docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md lines
209-230, keeping translated pages consistent with the English behavior.

In `@src/cli/account-extended.ts`:
- Around line 289-292: Update the cleanup-only output branch around cleanupOnly
and accountCleanupPending so it does not print “account cleanup completed” when
cleanup remains pending; emit wording that accurately indicates incomplete
cleanup while preserving the existing removal message for non-cleanup-only
requests. Do not change exit-code behavior unless explicitly required elsewhere.
- Around line 282-283: Make the Codex-specific fields in the account removal
JSON output symmetric: update the accountCleanupPending spread beside
catalogRefreshPending so it is always emitted for Codex accounts, including
false, while remaining absent for non-Codex accounts. Preserve the existing
boolean value and avoid changing unrelated removal behavior.

In `@src/codex/auth-api.ts`:
- Around line 1413-1426: Update the DELETE account flow around hasStoredAccount,
storedCredential, and deleteCodexAccount so credential-only legacy deletions do
not persist runtimeConfig when config.json is absent. Set persistMissingConfig
only when the operation is not cleanupOnly and a persisted config already
exists, while preserving persistence for stored-account deletions and allowing
credential removal to complete.
- Around line 1427-1443: Update the DELETE account route around
deleteCodexAccount so it handles SQLite busy-lock failures from
withConfigMutationLockSync and CodexAccountDeleteRollbackError instead of
rethrowing them. Map each case to the route’s documented lock-timeout or safe
rollback response, while preserving the existing
CodexAccountCleanupRetryConflictError and CodexAccountDeleteCleanupError
handling.

In `@tests/codex-auth-api.test.ts`:
- Around line 3682-3693: Add a regression test beside the existing DELETE
unknown-account test that exercises handleCodexAuthAPI with cleanupOnly values
such as "0", "true", "yes", and an empty string, asserting each returns status
400 and the exact "cleanupOnly must be 1 when provided" error; keep the request
otherwise shaped like the existing DELETE case.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: aec47c90-b9a1-4084-a3ba-97ee3385f995

📥 Commits

Reviewing files that changed from the base of the PR and between 637711b and bd15b9a.

⛔ Files ignored due to path filters (1)
  • assets/pr-account-cleanup-retry.png is excluded by !**/*.png
📒 Files selected for processing (36)
  • docs-site/src/content/docs/ja/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/ja/reference/management-api.md
  • docs-site/src/content/docs/ko/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/ko/reference/management-api.md
  • docs-site/src/content/docs/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/reference/management-api.md
  • docs-site/src/content/docs/ru/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/ru/reference/management-api.md
  • docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/zh-cn/reference/management-api.md
  • gui/src/codex-account-mutation.ts
  • gui/src/components/CodexAccountPool.tsx
  • gui/src/components/codex-account-pool-main-card.tsx
  • gui/src/hooks/useCodexAccountPool.ts
  • gui/src/i18n/de.ts
  • gui/src/i18n/en.ts
  • gui/src/i18n/ja.ts
  • gui/src/i18n/ko.ts
  • gui/src/i18n/ru.ts
  • gui/src/i18n/zh.ts
  • gui/tests/codex-account-pool-behaviour.test.tsx
  • gui/tests/codex-account-pool-pinned-badge.test.tsx
  • gui/tests/codex-account-pool-toast-tone.test.tsx
  • src/cli/account-catalog-refresh.ts
  • src/cli/account-extended.ts
  • src/cli/account.ts
  • src/codex/account-lifecycle.ts
  • src/codex/auth-api.ts
  • src/config.ts
  • structure/05_gui-and-management-api.md
  • tests/cli-account.test.ts
  • tests/codex-account-delete-atomicity.test.ts
  • tests/codex-admission-primitives.test.ts
  • tests/codex-auth-api.test.ts
  • tests/config-mutation-lock.test.ts
  • tests/native-claude-code-toggle.test.ts

Comment thread docs-site/src/content/docs/reference/cli/providers-accounts.md Outdated
Comment thread src/cli/account-extended.ts Outdated
Comment thread src/cli/account-extended.ts Outdated
Comment thread src/codex/auth-api.ts
Comment thread src/codex/auth-api.ts
Comment thread tests/codex-auth-api.test.ts
@chrisae9
chrisae9 force-pushed the agent/codex-account-delete-recovery branch from bd15b9a to 177d918 Compare August 9, 2026 02:24
@chrisae9

chrisae9 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/cli-account.test.ts`:
- Around line 898-907: Add a regression test in the account CLI test suite for
removing an orphaned main credential with `remove openai main --yes
--cleanup-only`. Mock or inspect the cleanup request to verify it uses
`?id=__main__&cleanupOnly=1`, and assert the CLI reports the cleanup result
while preserving the expected exit status.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3047f202-112a-4079-8992-84147b09d11d

📥 Commits

Reviewing files that changed from the base of the PR and between bd15b9a and 177d918.

📒 Files selected for processing (17)
  • docs-site/src/content/docs/ja/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/ja/reference/management-api.md
  • docs-site/src/content/docs/ko/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/ko/reference/management-api.md
  • docs-site/src/content/docs/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/reference/management-api.md
  • docs-site/src/content/docs/ru/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/ru/reference/management-api.md
  • docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md
  • docs-site/src/content/docs/zh-cn/reference/management-api.md
  • src/cli/account-extended.ts
  • src/cli/help.ts
  • src/codex/auth-api.ts
  • structure/05_gui-and-management-api.md
  • tests/cli-account.test.ts
  • tests/codex-auth-api.test.ts
  • tests/config-mutation-lock.test.ts

Comment thread tests/cli-account.test.ts
@chrisae9
chrisae9 force-pushed the agent/codex-account-delete-recovery branch from 177d918 to eca2d09 Compare August 9, 2026 02:44
@chrisae9

chrisae9 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/cli-account.test.ts`:
- Around line 911-927: Add a focused test next to the existing Codex
cleanup-only removal test for plain `remove openai main --yes` without
`--cleanup-only`. Assert the command is rejected with the main Codex App login
error, no DELETE request is sent, and the `__main__` account remains present.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8de666ce-e142-4798-bf3f-5131229747f4

📥 Commits

Reviewing files that changed from the base of the PR and between 177d918 and eca2d09.

📒 Files selected for processing (1)
  • tests/cli-account.test.ts

Comment thread tests/cli-account.test.ts
@chrisae9
chrisae9 force-pushed the agent/codex-account-delete-recovery branch from eca2d09 to e483e21 Compare August 9, 2026 02:49
@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Aug 9, 2026
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

⚠️ Deterministic hygiene checks failed.

  • unsponsored_surface — This changes an authentication, workflow, release-automation, or dependency surface. MAINTAINERS.md requires security review for these; ask a maintainer to apply maintainer-sponsored once they have reviewed it. Paths: src/codex/auth-api.ts.

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed; the review readiness checklist is complete.

Review readiness checklist

  • ✅ All CI tests are green on my local testing.
  • ✅ I pushed my PR to the latest dev commit.
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ✅ My PR is ready for review.

4/4 boxes ticked.

This pull request is already Ready for Review.
The review-ready label marks this PR as ready; review automation runs independently. If no CodeRabbit review appears, comment @coderabbitai review to request one.
Maintainers: @lidge-jun @Ingwannu @Wibias

@chrisae9
chrisae9 marked this pull request as ready for review August 9, 2026 02:50
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@github-actions[bot] The readiness gate is complete. I will review PR #1324 at e483e21033bc5eb19ddb7a54491e9c04c99f0f60.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@github-actions[bot] The readiness gate is complete. I will review PR #1324 at e483e21033bc5eb19ddb7a54491e9c04c99f0f60.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@github-actions The readiness gate is complete. I will review PR #1324 at e483e21033bc5eb19ddb7a54491e9c04c99f0f60.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/cli-account.test.ts`:
- Around line 143-166: Gate the cleanup-pending branch in the mock around the
codexOrphanAccountIds state so it only returns accountCleanupPending for
cleanup-only retries of recorded orphan IDs. Ensure unknown cleanup-only IDs
complete without pending state and are handled consistently with the server
contract, while preserving normal deletion behavior and failure-count updates.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 23f43f4b-f566-4fd9-9ff9-6ad9c8e84690

📥 Commits

Reviewing files that changed from the base of the PR and between eca2d09 and e483e21.

📒 Files selected for processing (1)
  • tests/cli-account.test.ts

Comment thread tests/cli-account.test.ts
@chrisae9
chrisae9 marked this pull request as draft August 9, 2026 02:53
@chrisae9
chrisae9 marked this pull request as ready for review August 9, 2026 02:56
@chrisae9
chrisae9 force-pushed the agent/codex-account-delete-recovery branch from e483e21 to 5319826 Compare August 9, 2026 02:56
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@github-actions The PR is ready for review. I will review the changes, including the authentication changes in src/codex/auth-api.ts.

A maintainer must complete the required security review and apply maintainer-sponsored after that review.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions
github-actions Bot marked this pull request as draft August 9, 2026 02:57
@github-actions
github-actions Bot marked this pull request as ready for review August 9, 2026 02:58
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@github-actions[bot] The readiness gate is complete. I will review PR #1324 at 53198262fa80fd98d76bf0d6e624e113c2aaa5e3.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@github-actions[bot] The readiness gate is complete. I will review PR #1324 at 53198262fa80fd98d76bf0d6e624e113c2aaa5e3.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@github-actions[bot] The readiness checklist is complete. I will review pull request #1324 at 53198262fa80fd98d76bf0d6e624e113c2aaa5e3.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Wibias Wibias left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verdict: REQUEST CHANGES

The recovery design is directionally strong, and the earlier CodeRabbit findings are addressed. I still found three merge blockers on the current head:

  1. Data integrity: rollback can delete a dangling/unresolvable config.json symlink after the guarded config writer correctly refuses to replace it.
  2. Recovery durability: the dashboard's only cleanup retry identifier lives in component-local React state, so reload/unmount/restart loses the recovery action after the account row is gone.
  3. Automation contract: --cleanup-only can report that cleanup is still pending but still exit 0, so scripts see success for the one operation they explicitly asked to complete.

Security/privacy review is otherwise good: cleanup errors are projected to fixed public state instead of leaking storage/token details; stale cleanup retries fail closed with 409 when absence cannot be proven; live runtime ownership is invalidated after the durable row deletion; and acquiring the SQLite commit-required lock before external writes closes the reader/COMMIT window.

Review/process state also is not merge-ready yet: I found no submitted human maintainer review on this PR; the prior CodeRabbit threads are resolved, but its latest review is paused/pending. The current-head React Doctor and Cross-platform CI workflow runs are action_required with no jobs, so hosted CI has not actually validated this head. The local test results in the PR description are useful evidence, but they do not replace the blocked hosted runs.

Do not merge until the three blockers below are fixed and hosted CI actually runs on the resulting head.

function restorePersistedConfig(configPath: string, previousBytes: string | undefined): void {
if (previousBytes === undefined) {
try {
unlinkSync(configPath);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔴 Blocking — preserve an existing dangling config symlink during rollback. existsSync(configPath) is false for a dangling symlink, so this path records previousPersistedConfig === undefined. The config writer deliberately refuses an unresolvable symlink (resolveWriteTarget), but when that save throws this rollback executes unlinkSync(configPath) and deletes the symlink itself. That turns a safely refused account deletion into destructive mutation of the user's dotfiles-managed config entry. Track whether there was truly no directory entry (for example with lstat) and only remove a file that this operation actually created. Add a regression test with a dangling config.json symlink.

const [reauthId, setReauthId] = useState<string | null>(null);
const [actionFeedback, setActionFeedback] = useState<string | null>(null);
const [actionFeedbackTone, setActionFeedbackTone] = useState<NoticeTone | null>(null);
const [cleanupRetryId, setCleanupRetryId] = useState<string | null>(null);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔴 Blocking — the dashboard recovery state is not durable. cleanupRetryId exists only in component-local React state. After the DELETE succeeds, the account row is gone; if this component unmounts, the page reloads, or the app restarts before cleanup succeeds, this ID and the Retry cleanup action disappear. The UI also intentionally does not expose the opaque ID, so the dashboard has no way to reconstruct the retry. This can leave the credential orphaned indefinitely. Make pending cleanup rediscoverable/durable (or provide another server-backed recovery handle) and add a remount/reload recovery test.

else if (classified.type === "codex" && removedActive && after.activeId === null) console.log(`openai: ${AUTO_NOTE}`);
else if (classified.type === "oauth") console.log(after.rows.length ? `${name}: active account is now ${after.activeId}` : `${name}: no accounts remaining`);
else if (classified.type === "api-key") console.log(after.rows.length ? `${name}: active key is now ${after.activeId}` : `${name}: no keys remaining`);
else if (cleanupOnly) console.log(accountCleanupPending

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟠 Blocking automation contract — --cleanup-only still succeeds when cleanup did not complete. This branch can print account cleanup is still pending, but cmdRemove still returns 0 below. Exit 0 is defensible for the initial delete because the account row was durably removed; for an explicit --cleanup-only retry, cleanup is the requested operation. Returning success when it remains pending makes shell automation silently accept a failed retry unless it parses human stderr/JSON. Return a non-zero result when cleanupOnly && accountCleanupPending (with stable machine-readable state preserved) and update the test that currently codifies exit 0.

@chrisae9
chrisae9 marked this pull request as draft August 9, 2026 03:07
@lidge-jun

Copy link
Copy Markdown
Owner

The incomplete-cleanup bug is real and the recovery direction is valuable, but the current diff still carries a destructive rollback edge. In src/codex/account-lifecycle.ts:107-114, restorePersistedConfig() unlinks configPath whenever no prior bytes were captured. Because existsSync at lines 185-187 reports a dangling symlink as absent, the write-then-rollback sequence can replace and then delete a symlink the user owns.

The retry contract also does not survive its most important boundary. gui/src/components/CodexAccountPool.tsx:69-70 holds the orphan account ID only in component-local state and retryCleanup() depends on it at lines 231-236, so a reload loses the only handle to the pending cleanup. In the CLI, src/cli/account-extended.ts:298-304 prints that cleanup is still pending and returns 0, which means automation reads a partial failure as success. The PR additionally moves every config mutation from BEGIN IMMEDIATE to BEGIN EXCLUSIVE in src/config.ts:2247 — a global locking-policy change rather than account-cleanup recovery.

We would merge a focused recovery PR that preserves pre-existing filesystem entries during rollback, makes the pending cleanup target recoverable from server-owned state after a dashboard reload, and returns a nonzero CLI status while cleanup is incomplete — with targeted rollback, reload-recovery, and exit-code tests, and the shared config transaction mode left alone. Any lock-mode change deserves its own PR with its own justification.

Closing this version because the genuine deletion-recovery fix is bundled with unresolved data-safety, persistence, CLI-contract, and global-locking concerns. The fail-closed design instinct here is right; it is the blast radius that blocks it.

@lidge-jun lidge-jun closed this Aug 9, 2026
luvs01 pushed a commit to luvs01/opencodex that referenced this pull request Aug 9, 2026
Stop the PR quality gate from marking review-ready when hygiene still fails (as on lidge-jun#1324), and re-run the gate when sponsorship or exception labels change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working intake: hygiene-blocked Deterministic PR hygiene checks failed review-ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants