Files
PaperClipAI/maps/feature-map/activity.md
T
DottaandPaperclip bd382eee53 fix(recovery): explain retained source verification failures (#17773)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Workspace recovery must prove the identity of retained work before
it uses an allocation.
> - The verifier rejects several different contracts with the same
`source_binding_invalid` code.
> - A saved Retry can therefore stop before file preservation without
enough evidence for a safe repair.
> - Operators need a bounded observation of the selected source without
another attempt or weaker guards.
> - This pull request records closed failure reasons and adds an
explicit read-only inspection on the run page.
> - The benefit is a precise next diagnostic step while the saved work,
intent, and ownership fences remain intact.

## Linked Issues or Issue Description

Refs: #17741, #17053. This is a diagnostic follow-up. It does not change
recovery admission or the retained-source acceptance policy.

**What happened?**

A retained-source recovery exhausted in `verify_execution` with only
`source_binding_invalid`. Run and task diagnostics could not distinguish
an invalid reference, lease policy, source binding, or reopened
allocation. The normal recovery-actions read can also revalidate
recovery state, so it was not a safe substitute for a current read-only
inspection.

**Expected behavior**

Record an allowlisted reason at the rejected guard. Allow a reader to
inspect one exact task/run/action without changing its attempts, saved
input, receipts, or ownership. Clearly separate the recorded failure
from current identity observations.

**Steps to reproduce**

1. Prepare a terminal native run with a retained-source action and a
lease policy of `reuse_by_environment`.
2. Attempt source verification. The guard must still reject that policy.
3. Open the failed run and choose Inspect recovery, then Inspect current
source. The diagnostic should name `lease_policy_not_retained` and the
allowlisted policy.

## What Changed

- Split existing source-binding guards into closed reason codes. Keep
each acceptance predicate and physical recovery action unchanged.
- Persist validated, path-free reason/policy detail with future system
recovery failures. Keep historical generic records compatible.
- Add an explicit query on the existing task recovery-actions GET. Exact
company/task/run/action selection bypasses read revalidation. Run
selection lists at most 20 actions; inspection stops before per-lease
lookup when a record has more than eight sources.
- Add a manual inspection control on native export-failure run pages.
Keep resolved retained actions inspectable. Show recorded failure and
current recorded-source identity separately.
- Update execution semantics and feature/access recipes. The shared type
is the normalized server/UI contract; it contains no provider payload or
secret.

## Verification

- RED: the prior verifier failed both reason assertions for rejected
warm policy and foreign-run lease binding. GREEN: the final focused
source/HTTP, system-state, and UI suites pass 23 tests. The UI follow-up
passes 8 tests after the review fixes.
- HTTP tests prove exact selection, cross-company denial,
resolved-action access, reused-allocation rejection, redaction, and
unchanged actions, runs, leases, tasks, wakeup receipts, workspace
operations, and activity. A nine-source case proves bounded inspection
while the existing worker verifier still accepts all nine valid sources.
- Review follow-up: show allowlisted saved detail beside a changed
current observation, preserve all listed actions, and follow
exact-action selection in verified/limited/error tests. The prior
component fails the saved/current drift regression in an in-memory RED
control; the current component passes. UI typecheck/build pass again.
- `pnpm -r typecheck` and `pnpm build` pass. Token gates, maps, module
boundaries, and `git diff --check` pass.
- Rebased onto master `46de15ff4b` without conflicts. Range-diff proves
both diagnostic commits are unchanged. On new head
`a7e2bc87fcea75e76b6b736304d1287257f71174`, all 23 focused tests, full
typecheck/build, token gates, maps, and module checks pass again. Both
fresh reviews are 5/5 with zero unresolved threads. Final exact-head
GitHub status is CLEAN: 55 success, 2 skipped, 1 neutral, no pending
checks or failures. The [ci / verify
aggregate](https://github.com/paperclipai/paperclip/actions/runs/40387002325/job/121802415824)
passed in eight seconds. All test/build/typecheck/E2E lanes passed.
- Existing full workspace recovery suite: 56/56 pass (103.5 seconds)
before the byte-equivalent rebase. `pnpm test:run` hit repeated embedded
PostgreSQL initialization failure before database-suite assertions and
was stopped. No full local suite pass is claimed. The owned external
`_test` database provided the focused HTTP/source verification. The
prior browser attempt also stalled at Network.enable before its click;
that attempt did not establish browser acceptance.
- Current-head local browser acceptance passes through the actual run
page: Inspect recovery lists the exact action, Inspect current source
shows recorded generic failure separately from the current rejected
policy, and reload resets inspection to the explicit control. Explicit
selection works again after reload. The app used isolated data, an empty
inherited environment, a paused synthetic agent, and no provider
credentials. Final state remains failed/exhausted with zero attempts,
zero wakeup receipts, zero workspace operations, and unchanged original
generic failure. The local app and temporary tab were stopped. This
proves the diagnostic journey, not the deployed source's actual lease
policy or its recovery.
- Final merge verification at
`a7e2bc87fcea75e76b6b736304d1287257f71174`: GitHub reports CLEAN and
mergeable. Both repository-required checks, `ci / verify` and `ci /
e2e`, pass, as does the exact-head Greptile check (5/5, zero unresolved
threads). The separate [Entire
trail](https://entire.com/gh/paperclipai/paperclip/trails/7) has no
recorded reviewer approval; no such approval is claimed. It is not a
configured GitHub merge gate.
- Initial local setup failures were distinct from product assertions:
localhost sandbox EPERM required scoped local access; a browser harness
import path was corrected. A test UUID type inference error and
historical native-export UI selection gap were corrected before the
green run. The live task remains blocked; this diagnostic does not claim
it recovered.

## Risks

- This change improves evidence. It does not prove provider termination,
local descriptor integrity, or successful file preservation, and it does
not repair the original source.
- Current inspection spans multiple database reads. It is an
observation, not a historical cause or execution authority. It performs
no provider/filesystem calls and starts no retry or executor.
- The optional persisted detail is backward compatible. Unknown values
and extra fields are excluded. Oversized source lists remain uninspected
through this explicit diagnostic path; physical recovery rules do not
change.

## Model Used

OpenAI Codex based on GPT-6, with code execution and browser tools. The
exact serving model ID and context window were 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 (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-27 08:21:28 -05:00

7.3 KiB

navigation
navigation
section sectionOrder order
Oversight and operation 70 20

Dashboards and audit trails

People inspect company health, recent activity, run history, and routine activity, then follow evidence back to the task or agent responsible.

Feature ID: activity.

Implementation: dashboard, live dashboard, audit hub.

Agent access: companion.

Sub-features

  • overview: activity/overview — inspect the company dashboard and live-work summary.
  • activity: activity/activity — filter and page through recorded actor/resource events.
  • runs: activity/runs — find executions and follow their task/agent context.
  • routine-audit: activity/routine-audit — inspect routine execution activity separately from its definition.
  • timeline: activity/timeline — use the available timeline view to understand work over time.
  • agent-commentary: activity/agent-commentary — browse attributed agent suggestions and complaints.

How to get to it (user POV)

dashboard

Open /dashboard or /dashboard/live.

activity-audit

Open /activity, /activity/runs, or /activity/timeline in the streamlined shell; legacy routes may redirect.

Driving it with Playwright and the Paperclip CLI

Preconditions: follow the baseline. Prepare known task mutations and completed/failed runs in a disposable company, recording their IDs and actors.

dashboard

Automated: dashboard service covers server aggregation; dashboard helpers is narrower UI helper coverage.

Manual: Compare the dashboard with the known fixture tasks and runs. Start and finish a small task, refresh/reload, and verify the summary changes and links reach the right records. Exercise empty data and a failed fetch.

activity-audit

Automated: activity service, audit runs, and routine audit cover these separate data/host layers.

Manual: Find a known mutation by actor/resource and a known run by status. Change filters, load more, and follow the source links. Reload the chosen view and verify no company leakage or duplicate events. Inspect a routine run from its audit entry.

On a native workspace export failure's run page, choose Inspect recovery, then Inspect current source on the matching action. Compare the recorded failure with the current recorded-source identity. Inspection is read-only and does not confirm provider termination or file preservation. Resolved retained actions remain inspectable. The control makes no inspection request until used. Source/HTTP regressions cover current identity, rejected policy, foreign/reused allocation, bounded lookup, redaction and unchanged recovery state; component regressions cover explicit selection, loading, failure and identity-only success. These checks do not establish recovery of a deployed task.

Case detail's View in Audit opens /activity?entityType=case&entityId=<case UUID>. The Activity filters include Cases actions and Case entities; the Case search accepts a UUID or human identifier such as CAS-C1 (Enter or blur applies the search). Scoped history names and links the case, and agent actors use their real avatars. Historical creation, field, status, link, attachment and label events from case_events appear alongside the already recorded handoffs and document events, without duplicating those mirrored records. Combined history passes retained case access before cursor pagination.

Focused regressions: Audit feed, Audit routing, and Postgres audit routes. These prove the component/API boundaries separately; follow the case-to-Audit link in the actual app to verify the assembled journey.

Issue activity is also available through GET /api/issues/{id}/activity. Agent authorization and sandbox bridge regressions cover this route separately from company-wide audit. Live sandbox agent access remains unverified; use the companion recipe.

Audit-event Load more and run listings differ: Runs currently loads at most 200 entries without pagination. The tested RoutineAuditActivity component has no registered activity-route host; inspect execution links actually offered by the routine rather than treating that component test as a reachable journey.

agent-commentary

Open Audit → Commentary (/activity/commentary). Search message text, filter by agent and suggestion/complaint, page through 50-message previews, and open a row to read the full message with its task/run links. Filters, page offsets and the selected entry are retained in the URL. Read access requires board company access and commentary:view, granted by default to all human company roles and backfilled for existing active human members. Task privacy applies to previews, counts and full messages; agent-action audit access is separate. All Audit tab destinations resolve in both the classic and streamlined layouts.

Storybook: production page and message journeys covers populated, filtered, long-message, paginated, empty, loading, failed, denied, linked-message, mobile and light states using synthetic API fixtures. These examples do not prove live database filtering or authorization.

Gotchas

  • Audit/activity events, run-log rows, first-party Telemetry, and operator OpenTelemetry traces are separate data paths.
  • A healthy stream or dashboard counter alone does not prove task success.
  • Cost and budget reports have their own recipe.

Storybook verification

runs

Capability ID: activity/runs.

Scope: ui Storybook: Mount AuditRuns selected status/agent/routine, linked task/agent, empty/loading/error/retry and 200-entry limit. Do not invent pagination. Production: GET /companies/{id}/heartbeat-runs and /routines/{id}/runs require company/read/privacy checks; real browser follows context links and confirms the referenced execution. Company run history defaults to 200 rows and caps explicit limits at 1,000. Summary contexts omit stored prompts and expand JSON once per returned row. The array response and run visibility/redaction checks remain in place. Agent detail links resolve older runs by ID outside the recent history page. Sources: Source: AuditRuns.tsx, heartbeats.ts, routines.ts. Tests: AuditRuns.test.tsx, heartbeat-run-privacy-routes.test.ts, routines-service.test.ts