Files
PaperClipAI/server
DottaandPaperclip 965184d296 fix(runner): reuse accepted confirmations on native continuation (#18283)
## Thinking Path

> - Paperclip coordinates agent work and human decisions.
> - Native agents receive accepted confirmations when their task
resumes.
> - A resumed run can repeat the original confirmation with the same key
and scope.
> - The interaction service rejects that replay because the source run
changed.
> - This PR returns the original acceptance only to its bound native
continuation.
> - Changed requests and newer proposals keep their existing approval
gates.

## Linked Issues or Issue Description

**What happened?**

A native agent received a human acceptance, then repeated the same
confirmation key and request. Paperclip returned a conflict because
`sourceRunId` differed. The agent then used a new key and created a
second pending confirmation. The task waited for another answer.

**Expected behavior**

An exact replay from the native run that received the accepted response
returns the original accepted record. It creates no request or wake.
Changed scope, another creator, an unrelated continuation, and a newer
proposal must still fail.

**Steps to reproduce**

1. Create a confirmation from a native run.
2. Accept it as a human.
3. Resume the same task with that accepted response in its saved native
input.
4. Repeat the original confirmation key and request.

Before this fix, step 4 returns `409 Interaction idempotency key already
exists for a different request`.

**Paperclip version or commit**

Reproduced against source `81ebe479`. The deployed failure was also
confirmed against Core `6a674716`.

**Deployment mode**

The failure occurred on Cloud. The regression uses the real native tool
authority and PostgreSQL 17 with synthetic data. The full fresh Cloud
journey is not yet verified with this fix.

No duplicate open PR or issue was found in the related
confirmation-replay and interaction-idempotency searches.

## What Changed

- Let the current run's parsed, identity-bound accepted response
nominate an internal replay of a plain confirmation or checkbox. Exclude
governed tool, secret, connection, and quality-review cards.
- Reuse the original accepted record only when the key, creator, and
full normalized request match. Preserve its source run. Reject a newer
confirmation.
- Keep ordinary source-run comparison and mutation receipts. Recheck
accepted cross-run reuse on cached calls and lost-ack recovery. An
absent original cannot create a replacement.
- Add real database regressions and document the replay contract.

## Verification

- Real PostgreSQL regression: the original replay failed with the
observed conflict, then passed.
- Cached replay regressions: two controls first returned stale
acceptance. Both now reject it.
- Final replay and recovery suite: 27 passed. This covers both plain and
checkbox confirmations, governed-payload exclusion, identity, company,
request changes, newer proposals, revised plans, absent receipts, absent
originals, and tool-key conflicts.
- Existing native-tool and onboarding admission suites passed with the
first 24 replay controls: 109 tests at `3cfd58e7`. The scope follow-up
reran all 27 replay controls.
- Existing interaction service and policy suites: 122 passed.
- Full `pnpm build` and `pnpm -r typecheck` passed at `3cfd58e7`. After
the scope follow-up, the focused 27 tests and server TypeScript check
passed. Required full Linux CI passed on the final head `eabdbd6b`.
- The full local Vitest suite was not repeated because the macOS
embedded PostgreSQL bootstrap failure is already documented. Relevant
suites used the supported external test database paths. Required Linux
CI remains pending.
- Final-head CI attempt 1 failed only the unchanged Antigravity login
success fixture. Its implementation and test match a previous passing
head. The exact failure cause is not retained. The original [failed
job](https://github.com/paperclipai/paperclip/actions/runs/41014308876/job/123927423551)
is preserved. The one failed-jobs-only retry request passed on the
unchanged final head. This confirms recovery, not the cause of the
original failure, and is separate from the Cloud journey.
- Full fresh Cloud onboarding and its dependent journey remain
unverified at this revision.

## Risks

An approval replay must not authorize new work. The service keeps exact
request and creator checks under the task lock. Newer confirmations and
ordinary downstream task and target checks remain effective. Normal API
callers cannot supply the internal replay nomination. No database
migration or public request-schema change is included.

## Model Used

OpenAI `gpt-6.1-sol`, ultra reasoning, with repository and shell tools.
The parent runtime metadata supplies this model identity. The context
window is not exposed. Independent review used the same model family.

## 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>
2026-10-30 01:53:45 -05:00
..