## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Teams file delivery saves a claim before each provider operation. > - A crashed operation can leave that claim unfinished. > - Periodic maintenance scans for abandoned claims even when none exist. > - This PR wakes recovery from committed changes and the saved claim deadline. > - Empty work becomes quiet while unknown effects remain safe to review. ## Linked Issues or Issue Description **What existing behavior does this improve?** Teams abandoned file-transfer recovery. This is slice 27, stacked on consent expiry #17590. **Current behavior** The remaining Teams maintenance callback scans every 30 seconds for expired transport claims. It runs from shared publication maintenance. **Proposed behavior** The Teams owner reconstructs existing claim deadlines at startup and reloads a transfer after its committed update. At expiry it clears the claim and preserves the existing unknown-outcome or conflict state. Normal receipt settlement removes the deadline. **Reason and benefit** Remove the last periodic Teams maintenance scan without resending a possibly delivered card or file. **Breaking changes** No schema or public API change. Explicit diagnostic recovery methods remain compatible. Consent expiry stays with its separate parent worker. ## What Changed - Add a Teams-owned worker for consent_sending, uploading, file_info_sending and conflict rows with a saved attempt expiry. - Notify from the existing versioned update before writes. Preserve transaction ownership and shared uncertain-write reconciliation. - Expose a narrow per-transfer recovery method that uses the existing lock order, integrity checks and atomic projection. - Remove the periodic Teams maintenance callback and its publication-maintenance invocation. - Add real claim, receipt, conflict, backlog, restart, precision, failure, drain and shutdown tests. Wire the owner through existing app admission gates. - Retain the existing signoff cancelled-run selection test and GitHub inline retry-window race assertion. - Document supported writers, remaining sleep limits and the failure ledger in `doc/idle-teams-attempt-recovery.md` and its linked audit. ## Verification Published head: `24c54399909105984e2a10f5869064984f69c472`, targeting master after consent #17590 merged at `4a89456bb3f9aef87cfe0e922e8b9d1a777a6c7e`. A normal ancestry merge reconciles the landed squash with the previously verified child. The complete 13-path binary patch is identical before and after reconciliation, and all 30 unrelated master paths are preserved. This adds no new worker behavior; the 239-case local evidence below belongs to the verified unchanged patch. All 58 current-head checks are now clean, including the complete required CI run. Greptile is 5/5 at this exact head. The current Ponytail turn is paused without a verdict, which is an explicitly authorized nonblocker; no failing review is waived. The complete 13-path slice preserves the reviewed attempt implementation and inherits the parent's report migration 0397, bounded consent worker and retention CI test repair. No new schema, queue table, shared scheduler contract, workflow or lockfile change is added by this duty. - **239 distinct selected cases pass:** 221 across five complete transfer/publication/consent/runtime/app-wiring suites, 16 selected real Board/Teams-authority/GitHub-retry integration cases, and two delegated Slack policy cases. Other chat integration cases (1,579) and connection-management cases (81) were skipped, not passed. Each database owner uses a new isolated PostgreSQL database. - Real Board publication saves an active attempt deadline; its confirmed receipt retires recovery, and SQL stays quiet afterward. The inherited consent producer and authority cases still pass. Lifecycle coverage exercises claim stages, unknown-outcome quarantine without repeating provider I/O, conflicts, rollback, restart, precision, backlog/fairness, failure recovery, drain and shutdown. The changed GitHub metadata/retry race passes without duplicate assessments. - The old server10 CI failure, run `40557802358` job `122390238707`, was a delegated Slack invitation rate-window assertion (2,122 passed/one failed/15 skipped in that shard). The verified parent already contains its Date-only fixture fix. Both linked and invitation cases now pass their full caller/target/shared-policy scenarios on a fresh server fixture; no duplicate policy change or new owned file was added. That old failure is preserved rather than called a pass. - Server production typecheck, build and module-boundary checks pass. Test files were executed; production typechecking does not statically check them. The existing test-only signoff cancelled-run selection fix is retained but was not executed locally in this acceptance; fresh remote E2E gates remain required. - [Current-parent acceptance and preserved failure ledger](https://github.com/paperclipai/paperclip/blob/24c54399909105984e2a10f5869064984f69c472/doc/plans/2026-10-25-teams-attempt-recovery-sleep-audit.md#current-consent-parent-preparation-and-acceptance-october-28) records current scope, commands, counts and limits. Earlier 235-case and combined-stack counts belong to their stated revisions and are not added to 239. The [stack ledger](https://github.com/paperclipai/paperclip/blob/24c54399909105984e2a10f5869064984f69c472/doc/plans/2026-10-24-recurring-server-sleep-stack.md) retains inherited failure history. No complete local repository suite, live Teams/Slack tenant, external wake, physical suspension or savings claim is made. - **Exact-head Greptile 5/5 and all 58 checks are clean.** Actual failing Ponytail findings must be repaired; a missing/stopped/paused turn without a verdict is an authorized nonblocker. An active no-verdict turn waits at most 30 minutes from its original request/start (25-minute monitor cutoff). Older reviews and parent checks are not treated as current passes. ## Risks - Recovery must not infer that an expired claim means a provider effect did not happen. It retains unknown outcomes and does not resend. - Late receipts must still match current claim identity. Current-state rechecks and existing protocol tests preserve this fence. - Supported deployment uses one active writer process through its owning DB client. Independent SQL and additional processes need a separate wake contract. - Cloud external alarm coverage and sleep eligibility are unchanged. Other chat duties still run periodically until their own migrations. - Voice-report parent review repairs are propagated: explicit single-active-writer scope and an indexed report window. Thirty report-worker/startup tests pass on the combined child. Fresh remote checks, older stack findings and final master reconciliation remain required. ## Model Used OpenAI GPT-6 through Codex, with repository inspection, tool use and code execution. The exact serving model ID and context-window size are not exposed in this session. ## 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 linked existing issues or described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links - [x] My branch name describes the change 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>
4.6 KiB
Teams abandoned attempts and idle work
Teams transport-attempt recovery now runs from committed transfer changes and saved claim deadlines. The shared coordinator and scheduler own its lifecycle. Together with consent expiry, this replaces the periodic Teams maintenance callback. It adds no table, schema or independent timer.
Durable obligation
A transfer in consent_sending, uploading, file_info_sending, or conflict
with attemptExpiresAt has an outstanding claim. The existing protocol writes
an attempt ID and a 90-second deadline before provider I/O. A normal receipt
clears both. A conflicting callback retains the original in-flight claim until
its deadline; the conflict is not proof that the original operation stopped.
The protocol's central versioned update registers an awaited notification before the write, within the existing transaction. This includes normal claims, settlement, callbacks and caller-owned operator resolution. The DB work-signal boundary owns outer commit, rollback and uncertain transaction settlement. Inserts create unused consent, so they do not create an attempt obligation.
Startup reconstructs eligible attempts in 100-row UUID pages. A committed hint reloads its transfer ID. PostgreSQL timestamps round upward to a millisecond. An inspection does not move the saved deadline. A changed claim is reloaded before recovery; settled or deleted rows remove the cached obligation.
Recovery preserves uncertainty
At the deadline, the existing Teams owner locks publication then transfer, checks integrity, and rechecks the current phase and deadline. It clears the expired attempt and changes a sending phase to its corresponding unknown outcome. Conflict stays conflict with its original reason and private evidence. Publication projection and transfer mutation remain atomic. Lock waits remain bounded.
Recovery does not call a provider, resend a card or file, manufacture a receipt, or assert that an unknown effect never occurred. A delayed foreground receipt still has to match its current attempt ID and phase. Existing operator resolution and on-use authorization rules remain unchanged.
Unknown outcomes with no live attempt are passive review evidence. Unused consent is owned by the separate consent-expiry worker. Neither keeps attempt recovery querying. Failed loads, locks or projections retain bounded retry work; fair batches allow healthy rows and other companies to progress. Worker errors redact SQL parameters and private transfer envelopes.
Lifecycle and ownership
The Teams module selects phases and deadlines. The existing protocol performs recovery. Shared startup only registers the worker and admission gates. The shared scoped worker coalesces writes, preserves dirty scopes through drain, reconstructs after restart, and joins in-flight work during shutdown. An unresolved write may still need transaction-status reconciliation while dispatch is paused; this is not an empty maintenance scan.
The explicit combined expireAndRecover and attempts-only diagnostic methods
remain available. Production processPublicationMaintenance no longer invokes
Teams recovery. Other chat maintenance reasons are separate pending migrations.
Supported writes use this process's owning DB client. Another active server or independent SQL writer requires a separate notification contract. Cloud external alarm coverage and conservative sleep eligibility are unchanged. A registered local deadline cannot wake a stopped host. This migration proves worker quiet, not measured provider suspension or fleet savings.
Verification
Real PostgreSQL tests exercise all sending stages, conflict during a live send, normal settlement, interrupted receipt persistence, saved deadlines across restart, quiet history, drain/resume, rollback, precision, atomic projection failure, 102-entry paging/fairness and shutdown. The real Board producer integration registers the worker before sending, observes the saved claim while the provider receipt is held, and verifies that the committed receipt disarms recovery. Existing Teams authority, consent and publication cases remain covered. See the audit and failure ledger.
Current parent acceptance is recorded in the audit's current-parent section: 239 selected cases pass, with the old inherited rate-window CI failure and its already-landed fixture fix preserved. Actual landed-parent reconciliation and fresh remote checks remain merge requirements; historical counts are not current full-workspace verification.