mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-31 14:16:39 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Managed AI connections keep the selected account in the secret store. > - Server quota refresh can receive a replacement token before its database save commits. > - That path currently writes an encrypted recovery file on the web server. > - Cloud web replacement should not need that file to use a saved account. > - This pull request saves the replacement directly and retries the same value in memory. > - The benefit is a smaller cloud storage contract with an explicit sign-in recovery limit. ## Linked Issues or Issue Description **What existing behavior does this improve?** Server-owned OpenAI quota refresh and credential persistence during web replacement. **Current behavior** Quota refresh checks local encrypted recovery storage before token exchange. It writes the replacement to that storage before the secret transaction commits. A replacement web receiver can therefore need the old web volume. **Proposed behavior** Required database reads and locks must succeed before exchange. The same logical refresh saves its returned replacement directly, with at most three save attempts. It checks the current secret after an uncertain commit response. A process that loses the unsaved replacement can require sign-in again. **Reason and benefit** Postgres remains authoritative. This removes new quota recovery files without adding another credential vault. Existing files remain readable for cutover. Local-only Google retirement keeps its existing behavior. Remote Google subscription sessions remain unsupported. Related public work: Refs #14056 for managed Codex credential handover. Searched open and closed credential-refresh pull requests; this change does not duplicate their provider login work. ## What Changed - Keep the exchanged replacement and its source generation in the current refresh operation. Save retries do not repeat OAuth exchange. - Reconcile a lost commit response from the saved credential. Grant changes, secret versions, session epochs, selectors, and revocation prevent a stale save. - Stop creating or preparing quota recovery files. Preserve existing record settlement and local Google compatibility. - Document the v1 sign-in limit and existing Runner persistence-before-completion contract. - Add PostgreSQL and controlled-provider regressions for save rollback, lost replies, revoked or changed authority, receiver process loss, and pending Runner credential handover. ## Verification - [Complete current-head CI](https://github.com/paperclipai/paperclip/actions/runs/41099132607) passed at `e4ed6551a707c814ddb2395a7358106b1e04857a`: 53 successful checks and two intended skips. This includes full typecheck, tests, build, and E2E gates. - `pnpm -r typecheck` and `pnpm build` passed at `1ebe75984be9bf19d518728d4ff440a2d7f3dbce`. Later branch changes only repair tests. Rebase adds an unrelated master UI performance fix; the credential and Runner handover source did not change. - Focused credential tests passed: 2 files, 160 tests (145.62s). Command: `pnpm exec vitest run server/src/__tests__/ai-connections.test.ts server/src/__tests__/plugin-task-credential-writeback.test.ts --maxWorkers=1 --no-file-parallelism`. - `pnpm test:run` was deliberately interrupted after 17m41s in its first general-server chat integration phase, before any suite result. The controller exited 130 and its wrapper exited 1. This is an incomplete local run, not a full local pass or an observed test failure. The coordinator stopped duplicate long local work; the complete current-head CI suite subsequently passed. All owned test and PostgreSQL processes were confirmed stopped. - Database tests use real PostgreSQL 18.6 with POSIX semaphores through a test-only loader. Provider requests use controlled fixtures; no production OAuth mutation was made. - Greptile reviewed current head `e4ed6551a707c814ddb2395a7358106b1e04857a` at 5/5 with zero comments. - The captured focused-test logs contain none of the replacement-token fixture values. - The receiver-loss test kills a separate Node process after one HTTP token exchange while PostgreSQL blocks its secret insert. A new receiver then uses the existing sign-in flow. - The Runner case rejects a real deferred secret commit. Provider completion remains uncalled until a new receiver commits the retained credential. - Initial setup failed because this host exhausted System V semaphore resources. Another setup attempt lacked built SDK entries. Both were setup failures, not passes. After setup repair, the first real run passed 159/160 tests; the remaining test asserted the retired directory-fsync contract. The replacement test forbids recovery writes and requires one committed exchange without a file. ## Risks - If all three saves fail and the producing server process exits, the unsaved replacement is lost. The next failed use can require sign-in again. This is the accepted v1 limit. - Existing unresolved recovery files still require inventory and settlement before their old volume is removed. This PR does not perform deployment or delete those records. - Local Google subscription retirement still needs its existing local recovery ownership. It is outside the supported remote cloud scope. ## Model Used OpenAI `gpt-6.1-sol`, with reasoning, repository tools, code execution, and controlled integration tests. The context window size was not supplied. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>