Files
PaperClipAI/server
DottaandPaperclip 91261d5a03 fix(server): preserve budget history for deleted resources (#18389)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Budget views show saved policies, incidents and spend for each
company.
> - A policy can remain after its agent or project has been deleted.
> - The overview currently stops when it cannot resolve that old
resource.
> - A current agent's budget then becomes unreadable during normal
setup.
> - This pull request preserves the historical row in display summaries.
> - Admission and policy changes still require a real company-owned
resource.

## Linked Issues or Issue Description

**What happened?**

The budget overview throws `Agent not found` when a saved policy
references a deleted agent. One old resource prevents the company from
reading its current budgets. The same problem affects historical project
policies and incident summaries.

**Expected behavior**

The overview should retain historical policy and incident IDs and spend.
It should display `Deleted agent` or `Deleted project` for a missing
resource. Read access must not grant permission to execute work or
change a budget for that resource.

**Steps to reproduce**

1. Create an agent and a budget policy for it.
2. Permanently delete the agent after its other dependencies have been
cleared.
3. Read the company's budget overview. The existing service throws
instead of returning its remaining current and historical rows.

**Paperclip version or commit**

The isolated repair starts from merged commit
`d9354bbfc35ef74333e90e596ce21dc8e59149b9` and integrates the exact
merged baseline test fix `8595efc20bda3ce20a9fbbf34a5d156a6fcf6d57`. It
also integrates the actual merged Antigravity auth fix
`18b1637b6371a6a6adade857e2a73654ee626fef` (#18254). The diff against
the selected merged parent remains two budget files.

**Related work**

Earlier reports and implementations: #11058 and #4333. This extracts the
product prerequisite from #18351 so it can qualify independently of that
journey's other dependencies. The change contains only the budget
service repair and four database regression cases.

## What Changed

- Resolve deleted agent and project scopes only when building display
summaries. Preserve their original IDs, policies, incidents and
accounting records.
- Reject a saved policy or incident that resolves to another company's
resource. Propagate other read failures.
- Keep missing-company resolution, work admission and policy changes
strict. Validate company, policy and incident scope bindings before
either incident action. A budget raise requires a live company-owned
resource. Historical dismissal may proceed only for a genuinely deleted
owned agent/project, and must reject live foreign or mismatched scopes.
- Add four canonical PostgreSQL regression cases: deleted agent history,
deleted project history, missing-scope admission and budget raises with
safe historical dismissal, and foreign/mismatched references. The
history cases also verify current ledger spend and unchanged stored
rows.

## Verification

- Real-service RED/GREEN against official PGlite with every canonical
migration: the original overview throws for deleted history; the repair
returns the historical IDs, incidents and spend while retaining current
budgets.
- Mutation regression RED/GREEN: missing-resource budget raises must
reject before writes; owned deleted-scope dismissal must reject its
linked pending approval, retain policy/agent/ledger data and incident
history, and remove the incident from the active list. Live foreign and
mismatched scopes reject both actions without mutations.
- Current integrated head `b3434f5ad05fd3067379352700c36bfe826179c4`:
all four canonical PostgreSQL regressions pass in [server
2/12](https://github.com/paperclipai/paperclip/actions/runs/41142588583/job/124361194077),
and all five existing budget-service tests pass in [server
7/12](https://github.com/paperclipai/paperclip/actions/runs/41142588583/job/124361194080).
Both use the CI merge against selected parent `18b1637`.
- Clean-build declaration typing passes in the current CI typecheck
gate. The earlier local source-alias no-emit check also passed,
including the canonical actor argument. The local worktree borrows
compiled dependencies from a sibling checkout; a later real-service
import was blocked by its stale `sandboxCreationOperations` export, so
clean-build CI is authoritative for the final integration. No production
workaround was made.
- `git diff --check` passes. Broad repository typecheck, tests and build
run in current-head CI rather than repeated locally. Native local
PostgreSQL could not start because this host exhausted its semaphore
pool; no global IPC settings or unrelated processes were changed.
- One unchanged Runner lane retry was authorized after a probable
intermittent close-settlement fixture failure. The [original
failure](https://github.com/paperclipai/paperclip/actions/runs/41142588583/job/124360234111)
occurred in `omitted-context` cleanup. A [fresh passing Linux
lane](https://github.com/paperclipai/paperclip/actions/runs/41142552195/job/124360110386)
passed the same case and all 1,998 tests with byte-identical entire
Runner and adapter-utils trees, lockfile, root package, scripts and
workflows, against the same merged base. The fixture has a five-second
close allowance with a 2.5-second suspension reserve; a host stall is
not proven. No budget path or changed close input was found. The [single
targeted
retry](https://github.com/paperclipai/paperclip/actions/runs/41142588583/job/124365812609)
passed the same case in 1,034 ms and all 1,998 lane tests; dependent
verification also passed. All 57 current PR checks are terminal and
green.
- The product helper requires all current CI and clean review before
merge. Actual QA budget-overview proof will run on the combined final
app before hiring qualification. No deployed success is claimed. The
older `b4863dd` artifact was never deployed; selected parent `18b1637`
adds sandbox/lifecycle changes and migration 0418, so whole-app identity
is not claimed. The budget module and relevant budget contracts remain
unchanged, and final hiring requires the combined final app with
explicit source identities.

## Risks

Budget summaries now return historical rows whose resources have been
deleted. These rows use explicit display names and preserve their
accounting data. They do not create a resource or relax work admission,
authorization or budget grants. Historical incident dismissal changes
only that incident and its linked approval; it does not resume work or
raise a budget. Cross-company references still fail closed. There is no
schema migration and no new background work.

## Model Used

OpenAI Codex, GPT-6 family. The session does not expose a more specific
backend model ID or fixed context window. Used reasoning, repository
tools, TypeScript and database test execution.

## 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 (the
PR description documents the display-only history and strict-mutation
contract)
- [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 18:36:36 -05:00
..