Commit Graph
5 Commits
Author SHA1 Message Date
DottaandPaperclip 30b753f614 perf(budgets): scope accounting and deliver enforcement asynchronously (#17046)
## Thinking Path

> - Paperclip manages AI agents and their paid work.
> - Budgets must prevent new work and stop reported overruns.
> - Cost settlement also ran serial lifecycle reconciliation for every
eligible company agent.
> - That made request latency grow with unrelated idle agents and
delayed results on stop delivery.
> - This change separates atomic admission and accounting from durable
asynchronous enforcement.
> - Scoped live usage detects overruns without writing provisional
ledger charges.
> - The result is constant query scope for ordinary settlement and
recoverable stop delivery.

## Linked Issues or Issue Description

**What happened?**

Settlement and budget checks entered company-wide lifecycle
reconciliation. A company with 1,000 unrelated idle agents performed
1,001 accounting transactions for one ordinary cost evaluation. User
requests could also wait for provider termination. Running usage
checkpoints did not enforce reported monetary exposure.

**Expected behavior**

Keep the final reservation gate authoritative. Commit charges, scope
blocks, and enforcement intent before returning. Deliver stop requests
after commit. Read only applicable policies and execution scopes for
ordinary charges. Stop long-running work when supported reported or
priced usage establishes an overrun.

**Steps to reproduce**

1. Create a disposable company with one company budget and idle agents.
2. Evaluate a charge below the budget with 0, 17, and 1,000 unrelated
idle agents.
3. Compare query counts, company accounting transactions, and duration.
4. Use the controlled partial-usage and delayed-stop fixtures to check
enforcement and request responsiveness.

**Paperclip version or commit**

The measured baseline is `6c9b87d0922f1ebfc43e8b0c36889ac5ba7b9837` from
`master`.

Related public work: Refs #16976, #2006, #3539, #13763, #14296, #16853,
#13075. These cover the affected service charge, cancellation, and
accounting paths. This change removes their shared reconciliation
overhead.

## What Changed

- Batch applicable policy exposure under the existing company accounting
lock. Preserve exact fractional money and zero-reservation dispatch
fences.
- Commit a durable final budget dispatch claim before provider I/O.
Retain a separate final issue/run ownership transaction through
synchronous handoff, without holding the company accounting lock or
awaiting provider work. Preserve native recovery lease checks and
duplicate handoff fencing. Browser handoff rechecks current policy; it
reuses a consumed rate slot only for the identical policy generation.
- Separate ledger spend, live observed spend, and effective held
capacity. Use the maximum of reservation and live observation for each
unfinished operation.
- Deliver budget cancellation through the existing coordinator.
Revalidate generations and persist queued/running stop fences before
external termination. Bound stop concurrency to four.
- Apply agent holds only to the affected agent. Project budgets leave
other projects running. Project real company transitions in bounded
lifecycle batches.
- Replace periodic broad reconciliation with durable pending work,
startup repair, receipt replay, and concrete retry/window deadlines.
Retain drain and idle-safety checks.
- Enforce accepted cumulative usage checkpoints without provisional
charges. Final accounting atomically replaces live exposure and settles
reservations.
- Add operator-gated budget spans, regression coverage, map updates, and
a real-PostgreSQL comparison harness. No schema or first-party telemetry
change.

## Verification

- Full workspace `pnpm -r typecheck` passes on the final ownership fix,
rebased onto `bbcf5dfe98`. Production `pnpm build` passes on final head
`4c5f4de8b1`. Map, module-boundary, token, and Storybook catalog checks
pass.
- Focused real-PostgreSQL coverage includes the 292-case rebased
accounting/dispatch run, 63 browser cases, 52 run-control/cancellation
cases, 42 policy-generation cases, 77 lifecycle/commentary cases, and
the exact Muse confirmation regression. Native executor unit coverage
passes all 768 cases. Final ownership coverage passes: 74
adapter/use-case cases, nine public regression cases, and the additional
deleted-project race. These exercise competing ownership, budget changes
and charges between phases, zero/nonzero duplicate claims, rollback,
recovery contention, read-only capacity rechecks, and controlled HTTP
startup after commit. Another 74 pure/startup/tracing cases pass. The
complete CI matrix and both 5/5 reviews passed on `1ac9b58`; its
external security scan identified a stale-owner handoff race. The final
fix restores synchronous issue/run ownership fencing after the
accounting transaction commits. Final head `8e84f55ce8` has fresh
Greptile 5/5 with zero new comments, Paperclip review 5/5, and a passing
security scan. The complete latest-head [CI
matrix](https://github.com/paperclipai/paperclip/actions/runs/39535189808)
passes, including budget, browser, Runner, build, and canary jobs. The
unchanged Runner close fixture passed on its sole same-head job retry.
- Broad local `pnpm test:run` invocations were stopped before required
source updates (rebase and review fixes). They are not claimed as full
passes. Final full-suite coverage comes from the complete latest-head CI
matrix; local focused coverage and the incomplete broad invocations are
reported separately.
- Reproduce performance with `pnpm --filter @paperclipai/server exec tsx
../scripts/benchmark-budget-enforcement.ts
--baseline-ref=6c9b87d0922f1ebfc43e8b0c36889ac5ba7b9837`; repeat with
`--reverse`. The harness uses disposable real PostgreSQL, 20 warm
samples per variant/count, and records raw timings, SQL/lock counts,
agent reads, unchanged agent state, and query plans. Final
production-source measurement revision:
`eff713a4f72c7f4b7a4002a701cb481d4bfccd95`; the extended harness is
committed in `4c5f4de8b1`.

| Unrelated idle agents | Baseline median / p95 | New median / p95 |
Baseline SQL / locks | New SQL / locks | New agent reads |
| --- | ---: | ---: | ---: | ---: | ---: |
| 0 | 1.80 / 2.33 ms | 2.99 / 3.88 ms | 5 / 1 | 7 / 1 | 0 |
| 17 | 15.53 / 19.55 ms | 2.24 / 2.60 ms | 90 / 18 | 7 / 1 | 0 |
| 1,000 | 978.35 / 1,790.43 ms | 2.16 / 2.52 ms | 5,005 / 1,001 | 7 / 1
| 0 |

- These measurements use local PostgreSQL 18.1 and Node 26.4.0 arm64.
They isolate the cost-evaluation core and complete admission path,
without hosted-region or provider latency. Prior-revision reversed-order
controls also preserved the constant query counts; the final
measurements above use the final production source.
- Complete reserve → final ownership gate → immediate offline provider
result is measured separately, with one responsible agent and one active
operation at each unrelated-agent count. Admission p95 baseline/new: 0
agents **11.54 / 29.77 ms**; 17 agents **9.31 / 27.62 ms**; 1,000 agents
**24.51 / 74.05 ms**. Baseline admission was already scoped; the
stronger final fence adds bounded overhead. New counts stay constant at
53 Drizzle statements, three transactions, two company-accounting locks,
and five agent-reading statements bound to the responsible agent. Zero
unrelated-agent reads, exactly one provider callback per sample, and no
leftover runs or holds. All admission scenarios stay below 250 ms. No
external provider calls are included.
- The partial-usage/delayed-termination fixture passed 20/20: receipt
persistence p95 13 ms, receipt return to observed durable Stop fence p95
28 ms, complete receipt-start-to-fence p95 50 ms, unrelated database
request p95 1 ms while termination was blocked. After releasing the
controlled termination fixture, acknowledgement p95 was 14 ms. These are
separately measured phases; fixture acknowledgement is not live-provider
termination latency.
- Models and provider deadlines are unchanged. No deployment, live
inference, or staging acceptance is claimed. A quiet 30-minute follow-up
waits for the merged revision on staging, then repeats classifier and
controlled budget-stop acceptance in staging, recording hosted
bookkeeping, queue delay, and actual provider acknowledgement
separately.
- Development failures retained: finalizer notification regressions
(fixed; 27/27 affected cases passed), invalid browser admission fixture
assumptions (fixed; browser coverage now passes 63/63), and first-head
lifecycle/dispatch CI regressions (reproduced and repaired). A
prior-head Cases E2E test hit its unchanged announcement-dismiss handler
race while opening a filter; the same journey passed on `1ac9b58`. The
external security review then found a stale-owner race between
accounting commit and provider entry; final verification covers a
competing run in that gap while retaining provider I/O outside the
accounting lock. Early PostgreSQL startup attempts hit local semaphore
pressure; serial reruns succeeded. The final-head Runner lane had one
failure among 1,823 tests: the unchanged `timeout-attachment` fixture
failed at its first process close after 6.28 seconds. The sole same-head
job retry passed all 1,819 active tests (four skipped), including that
fixture in 1.85 seconds. Three isolated local probes could not run
correctly because the Rust fake-provider fixture binary was absent;
cleanup masked the original startup failure. CI builds that fixture
through its normal lane. These probes are inconclusive and are not
counted as passes.

## Risks

- This changes accounting, lifecycle, and cancellation ordering. Durable
generations, source/sequence checks, ownership leases, and company
locking remain required for correctness.
- Provider stop acknowledgement can be slow or fail. Stop intent remains
pending until existing termination proof succeeds; cancelled row status
alone does not acknowledge delivery.
- Mid-run limits depend on provider usage reports or supported price
calculations. Providers that report only at completion cannot provide
exact mid-call detection.
- Signals are process-local wake hints for the supported
single-active-writer model. Durable state and startup recovery remain
authoritative.
- There are no migrations, new queue tables, or cached balances. Repeat
the classifier and controlled budget-stop acceptance after normal
rollout.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, tool use, code execution,
and parallel coding agents. The host does not expose the exact backend
model revision or context-window size, so those values are not asserted.

## 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-21 07:23:00 -05:00
DottaandPaperclip 813e808af4 Remove filesystem history authorization from workspace preparation (#16963)
Remove physical-root source/reader authorization and sticky directory classifications from workspace preparation. Preserve current task/run authority, app-record privacy, credential authorization, containment, and lifecycle/publication integrity.

Validate replacement selections against persisted new inputs and refresh verified checkout ownership so bounded reuse survives earlier workspace relocation. Add real PostgreSQL/Git regressions, a reproducible history-scaling benchmark, and documentation.

Full CI passed all 48 jobs and Greptile scored 5/5 at 3d5da6c259. Five preparation-guard medians improved from 20,512.99 ms to 52.22 ms on the 8,500-workspace fixture; these are not end-to-end startup timings.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-20 09:19:59 -05:00
DottaandPaperclip 6bec153410 fix(runtime): retain cancelled workspaces before reconstruction (#16700)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runs must preserve files when Stop ends a turn before its
result is saved.
> - The cancellation path could skip file retention and leave a prepared
remote workspace active.
> - An older controller could also admit an extra run while an earlier
lost-source hold was unresolved.
> - Rejecting every later run then prevented recovery even after that
extra run was stopped and its files were reconciled.
> - This change retains cancelled workspaces and records the exact proof
for a safely reconciled intervening cancellation.
> - Recovery can proceed without changing cancelled history, replaying
actions, or weakening execution gates.

## Linked Issues or Issue Description

Refs: #16583, #16690, #16696.

**What happened?**

Stop could acknowledge a native turn without recording its unsaved file
obligation. Reconstruction also rejected a later cancelled run after its
exact environment and files had been reconciled. The task could remain
inactive with an `in_progress` status, which the reconstruction endpoint
rejected.

**Expected behavior**

Retain unsaved files after Stop. Permit a board operator to reconstruct
from saved sources only after each intervening cancellation has a
confirmed stop and a file-only repair record. Preserve the original
failed export and the cancelled run.

**Steps to reproduce**

1. Prepare a native workspace and cancel the turn before a structured
result exists.
2. Inspect its file retention and remote lease state.
3. For a task with an older destroyed export, reconcile the later
cancelled run's exact files and unperformed actions.
4. Request reconstruction from verified same-task attachments.

## What Changed

- Pin prepared native files before cancellation settlement. Defer
teardown if pinning fails. Use the existing stop-only cleanup worker.
- Repair active warm and ephemeral sources, plus stopping and
confirmed-stopped historical cancellations in bounded startup and
periodic batches. Preserve the existing exact-source checks. Bound
row-lock waits and advance past a busy source.
- Accept only same-owner native run-only cancellations with no result or
current coordinator, confirmed stopped leases, and board file-only
repair with `not_performed` action outcomes.
- Save hashes of each intervening repair and recheck them at queue claim
and final dispatch. Reject changed evidence or another later run.
- Expose saved-source reconstruction in the issue API for inactive
`blocked` and `in_progress` tasks, and hide it when an execution or
checkout owner exists. Permit the same inactive source at submission.
Keep the source, owner, version, attachment, budget, pause and retry
checks.
- Update the shared evidence type, recovery runbook and capability maps.
Add an optional cancelled-native no-action confirmation to file
recovery, resetting evidence when its source changes. No migration, new
endpoint, permission or dependency.

## Verification

- The new fixture fails on the original validator with
`workspace_reconstruction_stale` after valid cancelled-run file repair.
- Focused source and Stop retention tests: 94 passed before the final
contention case. The subsequent three-suite run passed 123 tests,
including real PostgreSQL lock contention and public
startup/API/final-dispatch paths. The final narrow-query rerun passed
all 123 tests. Review correction: all 143 tests passed across four
suites, including real lock contention through the teardown boundary and
stopping/stopped allocations.
- Six broader cancellation, executor, heartbeat and restart suites: 831
passed, 9 existing skips.
- Final correction: all 145 backend tests and all 36 recovery UI tests
passed. Real contention covers both warm reusable and ephemeral sources.
Optional no-action confirmation defaults to uncertified, and changing
source clears evidence. Workspace `pnpm -r typecheck` and token gates
passed on these sources.
- Maps, module boundaries and Git whitespace checks: passed. Full `pnpm
build` passed on the final `4e8c0e73ac` revision as well as the prior
reviewed heads. A full local run of the preceding fix completed with
21,724 passes, 109 skips and three failures in webhook body limits, a
status-card timeout, and a port-allocation fixture. All three suites
then passed unchanged in an isolated rerun (209 tests). The full local
run remains recorded as failed; the final head's full CI passed (55
completed checks, no failures). A fresh full local run is also in
progress on the frozen reviewed head.
- Preserved failures: the first attempt lacked a built plugin SDK; after
building prerequisites, the regression reached the expected validator
rejection. Treatment tests caught the file-only action's deliberately
null continuation owner. A real lock test then caught the database
driver's wrapped timeout error. Both defects were corrected and
retested. Independent review then found a teardown race after a failed
retention write. A second review found active warm sources excluded by
the historical policy filter; the regression reproduced both warm
failures before correcting the query. Its real-row-lock fixture
reproduced the failure; the fixed release guard and historical
stopping/stopped cases pass. No checks were weakened.
- A pre-deployment walkthrough caught the issue API still hiding
reconstruction for an inactive `in_progress` task. The status/capability
baseline reproduced three failures, including inappropriate capability
flags for execution/checkout owners. The fix uses the same
inactive-state requirements as submission; its positive fixture reads
the assembled issue API before reconstructing. All 117 tests in those
three recovery suites pass, and all 28 heartbeat-recovery tests pass
separately. Full workspace typecheck passed again. Full build passed
with the exact `4e8c0e73ac` stamp; latest-head independent review is 5/5
with no open findings. All 55 latest-head checks completed with no
failures.
- Live tenant acceptance remains pending. No successful reconstruction,
export or warm-process proof is claimed by these local tests.

## Risks

- Stop retains unfinished work, so storage remains until file recovery
and explicit cleanup complete.
- Reconstruction remains held for unknown or performed external actions,
foreign owners, live or rebound environments, accepted results, changed
evidence, and unrelated later runs.
- The sweep examines at most five candidates per pass. It uses a fair
cursor and bounded transaction waits. It performs no provider call and
starts no new turn.
- Intervening verification reads only the needed JSON fields. The source
transaction still serializes recovery for the same task.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use and code execution.
The session does not expose an exact backend model ID or context-window
size.

## 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-18 01:33:11 -05:00
DottaandPaperclip 69ac928d2b fix(runtime): preserve bounded retries after workspace reconstruction (#16696)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - An operator can rebuild a destroyed workspace from saved task
attachments.
> - The first reconstruction run must pass current source and execution
checks.
> - A temporary bootstrap failure can create a bounded retry before
provider work starts.
> - The retry has a new run ID, so the first-run-only reconstruction
check rejects it.
> - This change verifies the retry chain back to the approved first run
and keeps current safety checks.

## Linked Issues or Issue Description

Refs #16690.

**What happened?**

After an operator records workspace reconstruction, a safe bootstrap
retry is cancelled before provider startup. The normal retry scheduler
creates the successor. The reconstruction check then rejects its
immediate predecessor because it expects the original failed export run.

**Expected behavior**

A verified automatic retry can continue under the same reconstruction
decision and remaining retry budget. Changed sources, unrelated
executions, uncertain outcomes, pause and later human blocks must still
stop startup.

**Steps to reproduce**

Record reconstruction with a retry budget remaining. Let its first run
fail before provider work starts with recorded bootstrap evidence. Use
the normal bounded retry scheduler and the locked dispatch gate. Before
this change, the scheduler succeeds but dispatch returns false.

## What Changed

- Verify the predecessor chain back to the recovery action's exact first
continuation.
- Check company, task, agent, terminal predecessor state and each
scheduler-owned wake. Reject cycles, foreign parents and forged wakes.
- Exclude only those verified predecessors from the unrelated-newer-run
check. Keep source hashes, original result identity and all current
execution gates.
- Reuse the existing reconciliation proof for failed predecessors. Keep
the original retry limit.
- Add real PostgreSQL scheduler and assembled-heartbeat regressions.
Update the recovery guide and feature map.

## Verification

- The baseline regression failed at final dispatch after the normal
retry scheduler created its successor.
- The corrected focused group passes 133 tests across reconstruction,
retry scheduling and dispatch. It admits two bounded bootstrap retries
and refuses a third. The assembled heartbeat enters the provider once
for an eligible retry and zero times after a controlled post-claim human
block.
- An intermediate negative case exposed missing predecessor-outcome
validation. Reusing the existing reconciliation proof fixes it. Deleted
sources, pause, forged wakes, foreign parents, unrelated runs and new
recovery holds remain refused.
- Full workspace typecheck and build pass on rebased head
`bd301ec8a703fa1cdc9e1db2638440d203e8d57a`. The rebased focused group
passes all 133 tests. All CI gates pass on that exact head, including
general/serialized tests, Runner, build and browser gates. Greptile is
5/5 with no unresolved threads. A clean full local `pnpm test:run` is
running; the local source stays frozen for that run.
- Module boundaries, maps and diff whitespace checks pass. Live staging
acceptance follows the qualified full Cloud deployment.
- The earlier full local run for #16690 failed while files changed and
its PATH hid `lsof`. All five affected suites then passed in a clean
run: 246 passed, three skipped. Those results do not establish a full
local pass for this follow-up.

## Risks

- Retry ancestry is a rare recovery path. Its primary-key reads grow
with the chain and stop at 64 predecessors. Ordinary runs perform no new
ancestry reads.
- Unknown effects and active recovery obligations stay held. This does
not reset budgets, change provider lifecycle policy, grant access or
replay completed actions.
- No schema migration or new API is included.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use and code execution.
The session does not expose an exact backend model ID or context-window
size.

## 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 (focused checks; full-run
scope is recorded above)
- [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-17 23:48:28 -05:00
DottaandPaperclip 7c7d2d8d2c fix(runtime): continue from saved sources after workspace loss (#16690)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The runtime must preserve saved work and prevent duplicate
execution.
> - Older cleanup could destroy a sandbox before its workspace export
finished.
> - The existing recovery controls require either the original sandbox
or recovered original files.
> - Surviving attachments can support a rebuild, but they do not prove
that missing edits were recovered.
> - This pull request adds an explicit reconstruction decision and one
fresh continuation through the normal execution gates.
> - Operators can continue useful work while the original failed run
remains truthful.

## Linked Issues or Issue Description

**What happened?**

A historical failed export can have an accepted result, a prepared
workspace descriptor, and a confirmed destroyed sandbox. Its notice can
also say `new_source_execution_path` and disappear. The task then has
neither a truthful original-file repair path nor a supported
reconstruction path.

**Expected behavior**

Keep the missing-file obligation visible. Let an authorized operator
choose surviving task attachments and record lost work and external
action outcomes. Start one fresh continuation after current execution
checks. Keep the old result and failed export intact.

**Steps to reproduce**

1. Seed a failed native export with a prepared descriptor and an exact
destroyed-lease receipt.
2. Resolve its notice with the historical `new_source_execution_path`
bookkeeping value.
3. Read the task. The baseline hides the hold even though no source
reconciliation exists.
4. With this change, choose **Continue from saved sources** and submit a
reconstruction decision.

Related public work: #16451 preserves healthy warm sessions. #16583
prevents destructive cleanup of unexported work. This change handles
historical source loss that those fixes cannot undo. Searches of open
and closed work found no equivalent reconstruction endpoint.

## What Changed

- Add a board-only reconstruction endpoint with `runtime:manage` and
task visibility checks.
- Validate the exact run, result, descriptor and destroyed lease. Reject
active copyback, competing owners, newer work, stale task status, and
foreign attachments.
- Record attachment hashes, missing work, and external action outcomes.
Preserve the original failed run, accepted result, prepared descriptor
and terminal failure.
- Hold other continuation paths until the durable reconstruction intent
admits its successor. Record that successor in the same transaction and
preserve the retry count.
- Add an operator control that distinguishes reconstruction from
original-file recovery. Update the recovery runbook and capability maps.

## Verification

- Exact baseline source returns no blocker for the destroyed-source
fixture. The same fixture returns a required recovery hold with this
change.
- New real PostgreSQL and assembled API/heartbeat suite: 25/25 pass. It
covers duplicate submissions, lost acknowledgement, context reset,
source identity, task ownership, concurrent execution attachment scope,
later human blocks, deleted sources and agent pause.
- Existing export retry, explicit continuation and recovery-action
suites: 386 cases pass. One new-fixture constraint error in the combined
run was corrected; the full new suite then passed.
- UI recovery suites: 46/46 pass across three files. They cover disabled
actions, loss acknowledgement, failure retention and runtime authority.
- `pnpm -r typecheck` and `pnpm build` pass. The first sandboxed
typecheck attempt could not open the TypeScript IPC socket; the
authorized rerun passed.
- Module boundaries, map checks, token gates and diff whitespace checks
pass.
- OpenAPI route coverage: 21/21 pass. The first CI head exposed a
missing endpoint registration; this head adds the registration and the
focused suite passes.
- Review identified a missing dispatch-time check and an isolated
attachment cache. Both are fixed. Claim and final handoff recheck the
exact successor, sources and current execution gates. A controlled
post-claim operator block prevents the assembled heartbeat from entering
the provider. The shared attachment cache refreshes uploads and removes
deleted selections.
- Final focused run: 180/180 pass across six suites, including
reconstruction, existing dispatch/stale-queue contracts and UI recovery.
- A second review reproduced cancellation by an already satisfied
historical connection card while the task was `todo`. Read-only
connection availability now works before checkout; active-task mutation
checks remain strict. The baseline failed two cases; after the fix all
74 connection and reconstruction tests pass, including revoked access,
pending questions and pending approvals.
- All current-head CI gates pass on
`9d197236da11fa24f1ceadf5589cb2b81179d824`, including general/serialized
tests, Runner, build and browser gates. Greptile is 5/5 for that exact
head with no unresolved threads. The full local `pnpm test:run` is still
running its serial server group; no full local pass is claimed. Live
staging recovery is pending deployment.

## Risks

- Reconstruction cannot restore missing bytes. The operator must
identify surviving sources and actions that must not be repeated. The
agent must verify those attachments before rebuilding.
- This path is limited to exact, confirmed destroyed remote sources with
an accepted result. Retained or uncertain sources keep their existing
repair path.
- No schema migration, credential change, budget increase or
warm-session policy change is included. Normal pause, ownership, budget,
approval and dispatch gates still apply.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use and code execution.
The session does not expose an exact backend model ID or context-window
size.

## 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 (focused suites; full local
run limitation recorded above)
- [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-17 22:57:10 -05:00