Commit Graph
13 Commits
Author SHA1 Message Date
DottaandPaperclip 124b2cd0ad fix(server): certify background deadlines for idle tenants (#19001)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Background services own future checks, retries, and recovery work.
> - An idle tenant can stop only when a durable wake covers its
remaining duties.
> - The current alarm catalog covers several domains but leaves these
owners blocked.
> - A saved future timestamp alone cannot prove that reconstruction or
admitted work has settled.
> - This pull request binds durable domain snapshots to the actual
registered worker revisions.
> - The tenant can hand off supported future duties and retain all
checks for uncertain or active work.

## Linked Issues or Issue Description

No matching public issue was found. Related work: [domain deadline
handoff #18656](https://github.com/paperclipai/paperclip/pull/18656),
[owned blocker diagnostics
#18632](https://github.com/paperclipai/paperclip/pull/18632), and
[completed history proof
#18646](https://github.com/paperclipai/paperclip/pull/18646). The
separate [native idle-session change
#18988](https://github.com/paperclipai/paperclip/pull/18988) covers
runtime retirement. [Far-future retry re-probes
#13534](https://github.com/paperclipai/paperclip/pull/13534) changes
recovery responsiveness after an upstream success; this change preserves
existing retry decisions.

**What happened?**

Future status-card, external-object, skill-sync, watchdog, retry, and
quota duties lacked complete owner-bound coverage in the idle deadline
proof. A completed quota task could also retain its monitor policy and
timestamp and remain blocked after the scheduler had disarmed it.

**Expected behavior**

A settled registered owner can hand off its exact supported future
deadline. Active work, dirty reconstruction, transaction uncertainty,
changed revisions, claims, unknown state, and unsupported duties keep
the tenant awake. Completed history retains its data and stops recurring
work when the owner has no remaining duty.

**Steps to reproduce**

1. Produce a supported future duty through its normal service.
2. Let the registered worker finish reconstruction and admitted work.
3. Request an owned idle report with the negotiated domain deadline
catalog.
4. Check the saved earliest deadline and generation before durable alarm
registration.
5. Stop and reconstruct the worker. Check that ordinary admission and
claims resume useful work once due.
6. Complete a quota task. Keep its saved policy and timestamp. Check
that linked unfinished work still blocks sleep and that settled history
does not.

**Paperclip version or commit**

The owned patch was qualified at
`699c8569fa34338dd75cdc5731381ec1e2efdb45`. Publication head
`491fac368ee72eaac8ae105d53e6bf6b305d8a6a` normally merges actual master
`039e0dad2c51c80251e1302a19c5566e039c357a`. All 43 owned files are
byte-identical. All 29 new upstream paths are preserved. The later
normal current-master integration is
`8c912e1ba4fc66397a7341ade59373af8075068f`, described separately below.

**Deployment mode**

Source checkout with real PostgreSQL 17 and a controlled local Node
process. No deployed alarm, tenant suspension, database suspension, or
fleet result is claimed.

## What Changed

- Add registered-worker reconciliation revisions and invalidate them on
stop.
- Keep status-card, external-object, and skill deadline interpretation
with their owners.
- Reuse the watchdog classifier against the supplied database snapshot.
- Validate the exact saved retry run and paired queued wake.
- Validate legacy quota source bindings and the current assignee or
reviewer policy.
- Preserve common issue scope, dependency, sibling, and state checks for
covered waits.
- Compose normalized owner snapshots within the existing bounded
deadline proof and recheck revisions after inspection.
- Bind actual service and worker instances from server startup. Missing
bindings preserve existing blockers.
- Retain completed quota policy and timestamps while independently
rejecting linked unfinished runs or wakes.
- Block unconsumed budget evaluation inputs through the owning queue
predicate. Accounting policy and settlement stay unchanged.
- Bind completed quota history through fixed-size UUID-array parameters,
preserve exact company/task/source associations, and guard external
references before the run-ID join.
- Batch watchdog subtrees and shared classifier facts without changing
the 64-query or two-second proof budget; preserve exact company pairing
for first-run evidence.
- Extend production-path regression controls and document supported
coverage and limits.

## Verification

Current integration head: `688abc6cac6016b9fb50e5832f81e2975ed5d49f`.
Fresh exact-head checks completed with **58 successes, three intentional
skips and one neutral review**, including aggregate `ci / verify`. The
complete current Greptile review is **5/5**. The complete current
Ponytail verdict is **Ship (4/5)**, with only optional cleanup of an
unused MCP proof input; both prior correctness findings are resolved.
All review threads and nested pages were inspected. The normal master
merges preserve the registered retry deadline owner and current startup
completion log after the same readiness await. The earlier focused
evidence below remains tied to its tested source revisions.


Current-master integration `8c912e1ba4fc66397a7341ade59373af8075068f`:

- Normally merge actual master
`46fb933b0155d183ce64a8bdc4950d1b58c926f6`. Every nonoverlapping tree
blob retains its owning parent across 14,044 paths. All 42 owner-only
files and 15 critical binding/proof/readiness files remain
byte-identical. Three automatic overlaps preserve the existing watchdog
binding, conservative unavailable-reader fallback and optional actual
owner arguments. The two scoped-deadline conflicts retain the entire
upstream resource-reservation/mid-pass admission/abort algorithm inside
the existing reconciliation revision/running/failure fence, with both
parent test sets.
- Actual TypeScript 7.0.2 server noEmit passed in 9.434 seconds, normal
source declaration layers in 12.102 seconds, and four selected
test/helper/config layers extending the actual CI configuration in 3.167
seconds. No compiler option weakening, heap override, donor declarations
or SDK replacement stub.
- Focused PG0 controls passed: 102 scheduler/proof/owner controls in
16.451 seconds, including all 21 scoped-deadline cases; 121 startup
controls; and all 107 unchanged instance-settings route cases in 6.456
seconds. The latter first hit a local prewire-guard
listener-registration race. Only the ignored guard was corrected to
register the same actual OS-bound server port immediately after native
listen returns. Closed, unknown, foreign, offhost and PG destinations
remain blocked. Original failure evidence is retained; product code and
assertions were unchanged.
- The exact current UI policy command now reports zero findings (0.362
seconds); its seven scanner controls pass. The earlier dependent PR used
an old scanner/source baseline under a newly enforcing trusted workflow
and reported 397 findings. Carrying the genuine current master resolves
that mismatch without editing unrelated UI sites or relaxing the gate.
- Every meaningful worker checked its executing PID/thread/preload hash
and matching receipt. PG0 controls opened no PostgreSQL sockets; all
owned processes exited. Original dependency-cache/DNS, ignored-harness
syntax/type and guard failures remain separate from product results.
- This is fresh semantic and focused runtime qualification, not a local
whole-repository or current-head PostgreSQL acceptance rerun. The
upstream workspace-busy parked-retry/terminal-holder notification path
remains unchanged by this merge and needs its separate current-graph
producer check. Historical six-case/scale results below stay tied to
their measured sources. A matching controlled default-cadence follow-up
is in #19191; no fresh current-head two-cycle or deployed suspension
claim follows from this merge.
- All 59 exact-head check contexts now pass (55 success, one neutral,
three intentional skips), plus the legacy security status. The complete
edited Greptile review is 5/5 for this exact commit, with all
root/nested pages inspected and no unresolved threads. Ponytail stopped
without completing its new turn; it supplied no new verdict or finding.
Prior actual findings remain addressed. Earlier scores/checks below
belong to their explicit earlier commits.


On frozen clean merged source `699c8569fa`:

- Real PostgreSQL acceptance: **6/6 passed**,83.483 seconds wall. Actual
retry producer creates the exact saved run/wake; stopped and
reconstructed owner resumes through current admission, one durable
start, real local process output and normal task completion. Includes
cancellation, drain arrival, retained quota history with queued-run/wake
negatives, watchdog review settlement and budget-input
empty/pending/consumed control using the actual owner.
- Affected coordinator, deadline, scoped-deadline, recovery and
composed-proof controls: **78/78 in five files passed**,32.114 seconds
wall, worker 1/no file parallelism.
- `pnpm exec tsc --noEmit -p server/tsconfig.json`: **passed**,17.467
seconds. Native TypeScript 7.0.2 and Node 24.22.2.
- PostgreSQL tests use one dedicated test database, matching
fixture/admin URLs, pool limit four, one worker, and no embedded
fallback. Every run recorded unchanged source hashes and a clean
checkout.
- The eight-second real-clock retry is a domain execution check. It is
below the Cloud minimum wake lead and is not a positive accepted hosted
sleep cycle.
- The completed quota-history product failure and original
fixture/protocol failures were preserved; the owning-reader fix passed a
real PostgreSQL red/green regression before the fresh merged six-case
pass.
- After runtime completion, the dedicated database had zero other
clients and no owned runtime processes. All three qualification process
PIDs exited. The coordinator independently audits and drops the
database.
- Comment-only cleanup has equal strict TypeScript parser ASTs across 15
files. The final lexical audit finds no added comments relative to
actual master. `git diff --check` passed.
- Earlier retry fixtures omitted responsible-user membership, advanced
JavaScript time past the real PostgreSQL lease clock, or produced stdout
without normal task completion. Corrected fixtures use real membership,
an eight-second real deadline, and ordinary task comment/completion. The
last case exposed legitimate disposition repair rather than duplicate
retry promotion.
- The quota and watchdog controls first ran before admitted work or the
existing 30-second reconstruction duty settled. The stronger tests
require an interim blocked report and then exact settled-owner proof.
Production deadlines were not changed. The separate
completed-quota-history defect was fixed in its reader and verified with
linked unfinished-run and wake controls.
- The status/object and skill owners reviewed the actual final startup,
route and post-backup bindings. Their domain source evidence carries
where token-equivalent. The master coordinator coalescing change was
reviewed separately. Historical domain PostgreSQL results are not
presented as fresh full-suite results on this head.

The later master merge adds retry predecessor cleanup checks under the
existing issue claim lock. The source audit confirms unchanged saved
deadlines and run/wake identities. The three actual retry
lifecycle/cancellation/drain cases passed on the batched candidate with
this parent (31.817 seconds). Those local dependency controls preceded
the current exact-head remote run. Native backup preservation and
TestOps changes from master are retained. No pass is inferred for
changed dependency behavior solely from unchanged owned files.

Review repair published as `643f1e7400`:

- The original reader returned `unknown` after seven actual watchdog
reviews settled across seven companies. The unchanged composed-report
regression passed after batching; the final reader passed in 61.841
seconds, including active queued-work and stopped-owner rejection.
- A separate two-company red/green control rejects terminal-run context
from another company as first-run grace evidence. Shared facts are
serialized once, with per-root IDs and review summaries.
- The affected recovery, proof and diagnostic unit controls passed 47/47
(14.575 seconds). Startup owner-contract fixtures passed 121/121 (10.589
seconds).
- Diagnostic PostgreSQL controls passed7/7 (12.406 seconds), including
the normal budget-input producer and its exact blocker reason. Initial
empty-state setup uses the same cleanup as per-case teardown when a
dedicated test database is reused.
- Actual repository `pnpm exec tsc --noEmit -p server/tsconfig.json`
passed 12.710 seconds with no heap override. Final source has no added
code comments; whitespace checks pass.
- The original query-budget failure, two-company discriminator, initial
cross-suite fixture failure and an interrupted incorrect local-driver
selector are retained separately. The interrupted run is not a pass.
Independent cleanup found zero owned clients or runtime processes.

Quota-scale repair published as `6696a37f8a`:

- The exact 10,000-row completed-history case reproduced
`MAX_PARAMETERS_EXCEEDED`:90,002 bound parameters exceeded the driver's
65,534 limit, and the composed report returned `unknown` despite settled
owners. Original failure and actual driver diagnostics are retained.
- Fixed pending-work queries use three typed UUID-array parameters plus
the result limit, keeping exact company/issue/source tuple bindings. The
primary run-ID column stays uncast; a guarded CASE validates the raw
external reference before conversion. The 10,000-row cap and
64-query/two-second proof budget are unchanged.
- The same 10,000-row composed-report case passed 18.860 seconds, with
unfinished run/wake rejection, malformed-reference safety and
conservative 10,001-row overflow. Its fixture derives retained history
from the actual quota producer and normal task completion, expands valid
persisted issue/source pairs, then starts the actual registered owners.
- The existing actual quota producer case passed 14.187 seconds,
including exact future deadline, retained completion history, unfinished
work, real foreign-company source references and noncanonical/malformed
references.
- Affected owner/proof controls passed 22/22 (26.444 seconds).
Production server noEmit passed 16.039 seconds.
- CI on 643 identified TS7034/TS7005 in the settled-watchdog fixture's
initially untyped collection. It is now explicitly typed. A separate
affected-entry semantic check extending the repository's actual
`server/src/__tests__/tsconfig.json` passed 15.093 seconds: six affected
tests, two owner files, ambient declarations and current imported
source, with unchanged strict/module/lib/path settings. The production
server config excludes that test directory and is not presented as
test-layer proof. No custom suppression or replacement SDK stub was
added.
- All runs were sequential with pool max 4, worker 1,
source/config/command hashes and cleared inherited
provider/LIVE/other-database variables. Cleanup found zero owned
database clients or local runtime processes. At prior head
`6696a37f8a5718cd0f79054969a0084462d41d47`, all required CI gates pass.
The exact-head inventory has 55 successes, one neutral review and three
intentional skips. Greptile is 5/5. The complete latest Ponytail verdict
confirms the quota finding is fixed; its only remaining note is optional
unused MCP proof state, not a behavior defect. All three review threads
are resolved. The earlier 643 result remains historical.

The repository-wide typecheck, tests, build and browser gates passed in
the prior `6696a37f8a5718cd0f79054969a0084462d41d47` CI run. The new
`8c912e1ba4fc66397a7341ade59373af8075068f` full CI also passes. They
were not run as a full local workspace command in the focused PostgreSQL
lease. Local evidence above uses bounded external databases and does not
claim embedded-cluster, live-provider or deployed-alarm qualification.

## Risks

- An unsupported or uncertain owner state must remain blocked. An
optimistic exemption could lose work while compute is stopped.
- Changes during reconstruction or inspection must invalidate the proof.
A memory-only timer is not durable alarm coverage.
- Current authorization, budgets, cancellation, accounting, and resource
ownership still apply on dispatch. The proof does not grant execution
authority.
- The supported writer model uses in-process transaction signals and
startup/resume reconstruction. Independent SQL writers and other
replicas need an explicit wake contract.
- Native, review, coalesced, and taskless retry variants remain
conservative until their owner cases qualify. Reviewer quota and hosted
alarm qualification remain open.
- The shared catalog remains opt-in. Legacy callers and missing owner
bindings retain their old blockers.

## Model Used

OpenAI `gpt-6.1-sol` was the configured model for the delegated service
implementations and reviews. OpenAI Codex, based on GPT-6, performed
managing review and integration. Both used repository tools and code
execution. The exact served backend snapshots and context-window limits
were not exposed.

## 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 and contains no internal
Paperclip ticket id
- [x] I have run tests locally and they pass on the final merged head
- [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 — exact current-head run passes
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups —
complete current-head review and all paginated threads inspected
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-06 13:48:55 -06:00
DottaandClaude Opus 5.5 958f9aa9f3 feat(issues): limit agent-created task trees to parent and child (#19312)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents split work into tasks. A task can have a parent task.
> - Today agents can nest tasks to any depth: parent, child, grandchild,
and deeper.
> - Deep agent-made trees are hard to follow, and an agent that works on
a child task makes grandchildren by default.
> - This pull request limits agent-created trees to two levels: a
top-level task and its children.
> - A request for a grandchild does not fail. The server puts the new
task beside the requester and tells the agent.
> - Board users keep full control. They can still nest to any depth.
Existing deep trees stay valid.
> - The pull request also records which task created each new task, so
the audit trail stays complete when the parent changes.

## Linked Issues or Issue Description

No public issue exists. This is the feature description. Related: #16853
(budgets that include descendant work) also reasons about task trees;
this change does not alter its traversal.

**Subsystem affected**

Issues (tasks): create, child create and move in the issue service and
routes. Agent tools, chat suggestions and creation provenance use these
paths.

**Problem or motivation**

Agents create subtasks as deep as they want. An agent that runs on a
child task gets that child as the default parent, so its follow-ups
become grandchildren. The trees become deep and hard to read. The parent
link is also the only record of which task created a follow-up, so that
record is lost when the parent changes.

**Proposed solution**

Limit agent-created trees to a parent and its children. When an agent
asks for a grandchild, put the new task under the requester's parent and
return `parentAdjusted`. Do not reject the request. Keep board users
unrestricted. Record the originating task in a new server-set
`origin_issue_id` column. Keep `origin_run_id` as the originating run.

**Alternatives considered**

Reject grandchild requests with an error. We did not do this, because
agents then fail mid-task. Add a database constraint. We did not do
this, because existing deep trees must stay valid and nesting can return
later.

## What Changed

- Add `MAX_AGENT_TASK_HIERARCHY_DEPTH` (2) and the
`IssueParentAdjustment` type in `packages/shared`.
- Add `resolveNewTaskParent` and `planIssueParentChange` in
`server/src/services/issues.ts`. `create`, `createChild` and `update`
use the agent limit by default (`parentDepthPolicy: "flatten"`).
- The issue create, `/children` and PATCH routes pass `allow_nested` for
board users. For agents, the routes check authorization against the
parent that the server actually writes.
- The requester keeps its behavior when the server moves a task beside
it: `blockParentUntilDone` blocks the requester, and the new task
inherits the requester's workspace and privacy.
- The server never moves a task above a low-trust boundary root that
contains the requester.
- These subsystems keep any depth, because they find their work by
parent: watchdog reviews, monitor recovery, email-channel placement, and
routines that a person configured.
- An agent move of a task that has children skips only the parent change
and returns `reason: "has_children"`.
- Add `issues.origin_issue_id` (nullable, `on delete set null`, indexed)
in migration `0434`. Only the server sets it. The `createdFrom` detail
field, the `createdFromIssueId` filter and task-creation provenance read
it first.
- Chat prompts now let a chat agent create one task, a task with
children, or separate tasks. The conversation is never a parent.
- The runner `create_task` tool accepts an optional `parentTaskId`. A
chat agent can create a top-level task and then put subtasks under it.
The run must be able to read and change the parent. A conversation is
never a parent. The depth limit still applies. Project tools map the
field to `parentId` through the issue route. The protocol manifest,
semantic contracts and eval fixture are regenerated.
- Watchdog runs that have an active watchdog keep their requested parent
on all create paths, because their access is limited to the watched
subtree.
- Fix a bug that the test drive found: the chat (MCP) `create_task`
ignored the requested `status`, so a `backlog` task became `todo` and
started to run. It now uses the same rule as the native tool.
- Update `skills/paperclip`, `doc/SPEC-implementation.md`, and add the
plan `doc/plans/2026-11-05-two-level-task-hierarchy.md`.

## Verification

- `cd server && npx vitest run
src/__tests__/agent-task-hierarchy-depth.test.ts
src/__tests__/agent-task-hierarchy-depth-routes.test.ts`: 19 new tests
for service and route behavior, all pass.
- Related suites (64 files: issues service, thread interactions,
privacy, watchdogs, provenance, runner tool authority, decisions,
routines, project tools): 1208 tests pass. Two tests changed because of
the intended behavior and pass now. Two `email-channels.integration`
tests fail locally because the test cannot find a bundled skill file
from this worktree path. This change does not touch that code.
- `packages/db`: migration safety, snapshot drift and journal tests
pass.
- Typecheck passes for `server`, `packages/shared`, `packages/db`, `cli`
and `ui` (local `ui` errors come only from generated Storybook catalog
files that are absent).
- Local test drive on an isolated instance with real Claude agents: 29
of 29 use cases pass, including an agent on a child task (follow-ups
placed beside it, with the notice) and a chat that creates a top-level
task with three subtasks.
- I did not run the full `pnpm test:run` or `pnpm build` locally. CI
runs them.

## Risks

- Behavior change for agents: some follow-ups that were grandchildren
are now siblings. The parent of the requester is woken when all its
children finish, which now includes these tasks.
- The runner `create_task` input contract adds one optional field, so
the protocol manifest and the pack contract change. The tool output does
not change: it shows the actual `parentId`, and the activity log records
`parentAdjusted`.
- Migration `0434` adds a nullable column, a foreign key and an index.
It does not backfill rows.
- `IssueCreationSource.run` is now nullable.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use
(shell, file edits, local test runs).

## 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 21:22:33 -06:00
DottaandPaperclip b6b57079b9 fix: evaluate status cards on committed changes and deadlines (#18401)
Reviewed and verified at 21795e222a.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 11:41:59 -05:00
DottaandPaperclip 42fd568cf8 Drive issue recovery from committed changes and exact deadlines (#18402)
Reviewed and verified at 11b49125db.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 09:41:27 -05:00
fengqing 05218571c3 fix(watchdogs): reject incomplete subtree scans (#15063)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task watchdogs verify stopped issue subtrees and restore valid work
paths.
> - A watchdog must read the full subtree before it can prove that all
paths stopped.
> - The current query stops after 100 levels and does not report omitted
children.
> - A running child beyond this limit can be absent from both review
dispatch and mutation checks.
> - This pull request reports an incomplete scan and blocks both
decisions.
> - Complete subtrees keep their current behavior and stop fingerprints.

## Linked Issues or Issue Description

Fixes: #15061

Related PRs: #11327 changes subtree loading but keeps the same depth
limit without a completeness result. #10331 changes mutation freshness
after watchdog writes. Neither patch covers this boundary. This patch
does not take code from those proposals.

## What Changed

- Keep the existing 100-level traversal limit.
- Check for an eligible child beyond the boundary in the same SQL
statement as the subtree read.
- Apply the same company, visibility, harness, and watchdog-origin
filters to this check.
- Return `incomplete` without a stop fingerprint when the scan omits
eligible children.
- Skip review dispatch and reject watchdog mutation revalidation for an
incomplete scan.
- Report incomplete scans through their own count and watched issue IDs.
Log each newly incomplete issue at startup or during periodic
reconciliation. Suppress unchanged results. Allow a new warning after
the issue recovers and becomes incomplete again.
- Add real PostgreSQL regressions for dispatch, a previously valid
mutation scope, the complete boundary leaf, and excluded children.
- Document the incomplete-scan behavior.

## Verification

- Base: `569c7203aa24b95440682983ce7940ba1d4247bd`. Head:
`06f68199656f979ef5eb4897851f0fbcbca592d3`.
- Before the fix, two real PostgreSQL regressions fail. The service
dispatches a review for a partial subtree. It also accepts a prior scope
after a running depth-100 child appears. The other 19 scheduler checks
pass.
- On the exact final head, `pnpm -r typecheck` and `pnpm build` pass on
isolated Ubuntu with Node 24.19.0, pnpm 9.15.4, and runner Rust 1.97.1.
- All 75 related tests pass. Run `pnpm --filter @paperclipai/server exec
vitest run src/__tests__/task-watchdogs-classifier.test.ts
src/__tests__/task-watchdogs-scheduler.test.ts
src/__tests__/server-startup-feedback-export.test.ts
src/__tests__/issue-watchdogs-routes.test.ts --maxWorkers=1`.
- Full `test:run` coverage passes across 29 logical groups: all official
stable-runner lanes plus supplemental service and script tests. The
selection covers all 900 server source test files without duplicate or
omitted selections. It also includes UI, CLI, and other workspace
projects.
- A separate validation tree applies both this PR and #15067 to upstream
`994d6edcdd4e15d5f9cc5cf8c135ac599104b86a` without conflicts. Type
checks, the build, and all 98 related tests across five files pass. Both
public PR heads remain unchanged.
- Four full server lanes required test-process environment corrections.
The host DNS search suffix resolved a `.invalid` fixture to an address.
Ancestor project authentication settings affected hire fixtures. The old
path-isolation tool also failed test imports with `EFAULT`. The exact
base has the same failures: 8 failed and 128 passed assertions without
isolation, then three failed imports with the old tool. All 136 checks
pass on both the base and this head with the corrected isolation. All
four original full lanes pass with the corrected tool, a resolver
without a search suffix, empty ancestor project settings, and the
standard Node path. No assertion or wait limit changed. The host
configuration remains unchanged.
- Earlier interrupted Ubuntu and Docker runs are retained and are not
counted as passes. This exact-head Ubuntu run passes the original chat,
port-conflict, and serialized lanes. The causes of the earlier host-loss
and timing failures are not fully established.
- The startup import regression in an earlier revision is fixed by a
diagnostics module with no database dependencies. All 21 startup checks
pass.
- Exact-head CI, including the added scans after marking the PR ready:
54 successful checks and 2 skipped checks. Greptile: 5/5, no outstanding
findings or follow-ups. Both review threads are resolved.
- The final audit rechecked issue authors, assignees, comments, 206 open
watchdog search results, root functions and fields, source history, and
related diffs. The latest upstream is
`994d6edcdd4e15d5f9cc5cf8c135ac599104b86a`. Its new patches do not cover
this root. No competing root repair was found within the audited scope.
The issue has no assignee or new comment.
- No model provider, production database, or user instance was used.
This verifies service behavior, not a full HTTP authorization bypass.

## Risks

- A subtree with eligible children beyond 100 levels now waits instead
of running a review. This is a deliberate safety boundary. It remains
blocked until the scan can include the full subtree.
- The boundary check adds a child-existence lookup to the existing
recursive query.
- No schema migration is required. Complete subtrees retain their
fingerprint format.
- This does not add unlimited traversal or close the separate race
between a subtree snapshot and later source mutations.
- The configuration lifecycle defect in #15060 is handled by separate PR
#15067. This branch does not include its schema or configuration
changes.

## Model Used

- OpenAI Codex, based on GPT-6, assisted with source analysis,
implementation, and test execution. The exact serving model ID and
context window are not exposed in this session. The agent used
reasoning, shell tools, GitHub CLI, and real PostgreSQL tests.

## 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
2026-10-26 20:53:47 -07:00
Ash Simons 550e959934 fix(task-watchdogs): deliver board instructions and stopped leaves in the wake payload (#13771)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task watchdogs wake an agent when a watched issue subtree stops
moving.
> - An operator can write `instructions` on the watchdog record. The
wake prompt has a slot for this text in the "Task Watchdog Mandate"
block.
> - The producer writes `customInstructions` and `stoppedLeaves` at the
top level of the wake payload. The normalizer reads them only from the
nested `taskWatchdog` object. Thus the normalizer drops both fields on
every watchdog wake.
> - The agent then sees "No board-supplied watchdog instructions"
although the record holds an instruction. The operator cannot see this
failure, and the agent cannot see it either.
> - This pull request puts both fields in the nested `taskWatchdog`
object.
> - The benefit is that operator instructions and the stopped-leaf list
reach the agent again.

## Linked Issues or Issue Description

No public issue exists. This is the bug description (bug_report
template).

**What happened?**
`watchdogWakeContext()` in `server/src/services/task-watchdogs.ts`
writes `customInstructions` and `stoppedLeaves` at the top level of the
wake payload. `normalizePaperclipWakePayload()` in
`packages/adapter-utils/src/server-utils.ts` reads
`payload.taskWatchdog` only. The two fields are lost. The "Task Watchdog
Mandate" block always shows "No board-supplied watchdog instructions.
Apply the mandate above." The "Terminal / stopped leaves to verify"
section never shows.

**Expected behavior**
When the watchdog record has non-empty `instructions`, the wake prompt
shows that text. When the subtree has stopped leaves, the prompt lists
them.

**Steps to reproduce**
1. Create a task watchdog on an issue. Set a non-empty `instructions`
value.
2. Let the watched subtree stop, so that the watchdog triggers.
3. Read the wake prompt of the watchdog agent. It shows the "No
board-supplied watchdog instructions" line.
4. `GET /api/issues/{id}/watchdog` still returns the non-empty
`instructions` value.

**Paperclip version or commit**
Reproduced on `master` before this change. The new test in this PR fails
on `master`.

**Agent adapter(s) involved**
Not adapter-specific (core bug). The drop occurs in the shared
wake-payload normalizer.

## What Changed

- `server/src/services/task-watchdogs.ts`: add `customInstructions` and
`stoppedLeaves` to the nested `taskWatchdog` object. Map each stopped
leaf to the shape the normalizer expects (`issueId` becomes `id`). Keep
the top-level copies, so that other consumers do not change.
- Add a test for the full path: real service, real wake payload,
`normalizePaperclipWakePayload`, then `renderPaperclipWakePrompt`. The
test also asserts that the "No board-supplied watchdog instructions"
line is absent.

## Verification

- Run from the repo root:
  ```
  npx vitest run server/src/__tests__/task-watchdogs-scheduler.test.ts \
server/src/__tests__/task-watchdogs-classifier.test.ts \
server/src/__tests__/task-watchdogs-incident-fixture.test.ts \
                 server/src/__tests__/issue-watchdogs-routes.test.ts
  npx vitest run packages/adapter-utils/src/server-utils.test.ts
  ```
- Local result: watchdog suites 52 of 52 pass. `server-utils.test.ts`
117 of 117 pass.
- The new test fails on `master` because
`taskWatchdog.customInstructions` is absent. It passes on this branch.
- All Paperclip CI gates on this PR are green. Greptile gives 5/5.

## Risks

- Low risk. The change adds fields to a nested object. It does not
remove fields.
- No schema change, no migration, no data write.
- Behavior change: agents now receive operator instructions that they
did not receive before. This is the intended result.
- Rollback: revert the single commit.
- Note: the normalizer field name is `terminalLeafSummaries`, but the
classifier fills `stoppedLeaves` with non-terminal stopped leaves. The
renderer heading ("Terminal / stopped leaves to verify") covers both.
This PR does not rename a public payload field. Maintainers can align
the names in a separate change.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Provider: Anthropic Claude, Opus family, used through Claude Code as
an agent with tool use and shell execution.
- This PR description revision: `claude-opus-5-5`, 1M context window.
- The model found the cause, wrote the fix and the test, and ran the
test suites. A human owns the account that opened the PR.

## 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)
- [ ] 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
- [ ] I have updated relevant documentation to reflect my changes (not
applicable: no documented behavior changed)
- [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

Duplicate search: I searched open and closed PRs and issues for
"watchdog instructions" and "watchdog customInstructions". I found no
related PR or issue.

Branch name: the branch name has an internal prefix. If the maintainers
want it, I can open the same commit again from a `fix/...` branch.
2026-10-15 15:47:54 -07:00
DottaandPaperclip 10d0555189 fix(interactions): authorize resolvers consistently (#11376)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Issue interactions give agents and people a structured decision
record.
> - Resolver routes used different authorization rules.
> - Some routes blocked valid agents, including task watchdogs with
normal issue access.
> - The API did not show who could resolve a pending interaction.
> - This pull request gives every interaction kind one resolver policy
evaluator.
> - The benefit is a clear decision path with consistent governance and
company isolation.

## Linked Issues or Issue Description

Fixes: #8087

Refs: #7403

Related PR: #11082 proposes board-only confirmation rules. This change
keeps human-only review as an explicit policy.

**What happened?**

Agents could create issue interactions. Some resolver routes still
required board access.

This left valid agent confirmations pending. Task watchdogs could see
the same problem without board identity.

**Expected behavior**

Every interaction kind must use one resolver policy contract.

The contract must support `anyone`, `not_creator`, and `human_only`. It
must also apply all normal governance controls.

**Steps to reproduce**

1. Create a `request_confirmation` interaction as an agent.
2. Resolve it with another authorized agent.
3. Observe the board-only denial.

**Paperclip version or commit**

The problem exists on `master` before this change.

**Deployment mode**

Local development with `pnpm dev`.

## What Changed

- Add canonical policies for `anyone`, `not_creator`, and `human_only`.
- Use one server evaluator for every interaction kind.
- Apply named addressees, company limits, review rules, and task
watchdog scope.
- Charge cross-issue resolutions to the existing per-run action limit.
- Return the effective resolver audience in attention and interaction
data.
- Show the audience, governance choices, and denial reasons in the board
UI.
- Add telemetry, API documents, product documents, and regression
fixtures.
- Add migration provenance for safe legacy behavior.
- Make migration `0218` safe for complete replays and partial prior
runs.

## Product Rules

- An interaction records a response. It does not grant authority for the
next action.
- `anyone` lets any authorized issue participant respond.
- `not_creator` requires a responder other than the interaction creator.
- `human_only` requires an authorized person.
- A named addressee, company policy, or governed action can narrow the
audience.
- These controls cannot widen the audience.
- A task watchdog uses the same rules as an ordinary agent.
- A task watchdog does not receive board authority.
- An agent resolution on another issue uses the shared cross-issue
action limit.
- Legacy pending interactions keep their earlier restrictions.
- The UI shows the effective audience and a permanent denial reason.

## Verification

- `pnpm --filter @paperclipai/db check:migrations`
- `pnpm --filter @paperclipai/db typecheck`
- `pnpm exec vitest run
packages/db/src/issue-thread-interaction-resolver-policy-migration.test.ts`
- The focused PostgreSQL test applies migration `0218` twice.
- The test also completes a partial prior run and preserves existing
provenance.
- The latest GitHub head has 29 successful checks.
- The opt-in Storybook visual check skipped as expected.
- Greptile reports 5/5 with no open comments.

## Risks

- New interaction writes use `anyone` by default.
- Callers must select `not_creator` or `human_only` when they need
stricter review.
- Legacy pending interactions keep the old creator and human
restrictions.
- Migration `0218` fills only missing provenance fields during recovery.
- Cross-issue resolutions can reach the existing action limit.
- The shared evaluator affects every interaction kind.
- Route, service, database, shared contract, and UI tests cover these
rules.

> This work matches the Agent Reviews and Approvals direction in
`ROADMAP.md`. It does not duplicate a planned item.

## Model Used

OpenAI Codex, GPT-5. The runtime does not expose the exact deployment ID
or context window.

The agent used reasoning, repository tools, shell commands, and 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 linked public issues or described the issue with the
required labels
- [x] I have not referenced internal Paperclip issues or links
- [x] My branch name describes the change and contains no internal
ticket id
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have considered and documented the risks
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open comments
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-16 13:46:50 -05:00
DottaandPaperclip c481be44e3 fix(task-watchdogs): deduplicate unchanged stopped-state wakes (#10207)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Task watchdogs review issue subtrees when no run or queued wake
keeps work live
> - Pending human interactions and approvals are valid stopped states
that still need one watchdog review
> - The existing fingerprint included volatile activity timestamps, so
unchanged stopped trees could wake repeatedly after comments, documents,
work products, or sibling completions
> - This pull request fingerprints only review-material leaf and wait
state, persists the reviewed snapshot, and suppresses shrink-only
repeats
> - The benefit is one review per materially new stopped state without
weakening liveness classification or hiding human waits

## Linked Issues or Issue Description

### What happened?

Task-watchdog stop fingerprints changed for metadata-only activity and
completed siblings, producing duplicate wakes after an unchanged stop
had already been reviewed.

### Expected behavior

Pending interactions and approvals remain classified as stopped, but a
reviewed stopped state only wakes again when waits, non-terminal leaves,
status, assignment, or blockers gain material changes.

### Steps to reproduce

1. Review a stopped watched subtree with a pending human wait or
multiple non-terminal stopped leaves.
2. Add only comment/document/work-product activity, or complete one
stopped sibling without changing the wait set.
3. Observe a duplicate wake from the timestamp-heavy fingerprint.

Related public work: Refs #9452 for overlapping task-watchdog service
edits and #10043 for related no-op fingerprint suppression.

## What Changed

- Added fingerprint v2 over non-terminal material leaves plus
subtree-wide pending wait ids, excluding volatile timestamps while
retaining them in wake context.
- Added nullable observed/reviewed JSONB stop snapshots and shrink-only
reviewed-state suppression with legacy exact-fingerprint fallback.
- Added pending interaction kinds and approval ids to watchdog wake
context, review comments, and comment metadata.
- Added classifier and scheduler coverage for waiting-leaf liveness,
metadata stability, sibling shrink suppression, material changes,
snapshot promotion, legacy rows, and unchanged idempotency keys.

## Verification

- `pnpm --filter @paperclipai/server exec vitest run
src/__tests__/task-watchdogs-classifier.test.ts
src/__tests__/task-watchdogs-scheduler.test.ts` — 2 files, 36 tests
passed.
- `pnpm --filter @paperclipai/server typecheck` — passed.
- `git diff --check origin/master...HEAD` — passed.

## Risks

- Fingerprint version 2 intentionally re-fingerprints every currently
stopped watched tree once after deployment, causing a one-time wake
burst before the new reviewed snapshots are established.
- Migration `0191_task_watchdog_stop_snapshots.sql` only adds two
nullable JSONB columns with no backfill; legacy rows continue
exact-fingerprint behavior until a post-deploy review promotes a
snapshot.
- PR #9452 edits the same service file; whichever lands second may need
a trivial rebase.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, exact model ID `gpt-5.6-sol`, high reasoning mode, with
repository tool use and code execution. The runtime did not expose a
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
- [ ] 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-07-25 08:34:41 -05:00
70ce005bef Ensure worktree execution starts only after activation (#9374)
## Thinking Path

> - Paperclip is the open-source control plane people use to manage AI
agents and their work.
> - Its scheduler, routines, and heartbeat services decide when agents
automatically begin work.
> - Experimental per-worktree execution is useful for isolated
development, but enabling it previously allowed automatic services to
consider an existing backlog.
> - A worktree activation must therefore create a durable eligibility
boundary rather than merely toggle execution on.
> - This pull request records an activation cutoff and applies it
consistently to automatic routine and heartbeat dispatch.
> - The result is that an enabled worktree executes only work created
after its own activation, while non-worktree behavior remains unchanged.

## Linked Issues or Issue Description

**Problem type:** Bug / safety regression

**Summary:** Enabling experimental run execution in an existing worktree
could start automatic scheduler, routine, watchdog, and heartbeat
activity for work created before that worktree was explicitly armed.

**Expected behavior:** A worktree that has execution enabled only
considers automatically dispatched work created on or after its
activation timestamp. Ambiguous activation state fails closed.
Non-worktree instances keep their existing behavior.

**Related public work:** Refs #8275 (runtime worktree policy gating);
this PR adds an activation-time boundary for automatic execution rather
than changing the general runtime policy.

## What Changed

- Persist a worktree execution activation timestamp and originating
instance ID; stamp them only when the experimental toggle changes from
disabled to enabled.
- Resolve activation state fail-closed when the cutoff is missing,
invalid, disabled, or belongs to another instance.
- Gate automatic routine scheduling, webhooks, watchdog activity, and
heartbeat selection at the activation cutoff; manual runs remain
available.
- Share the canonical worktree truthy-environment helper across routine
dispatch and agent inbox filtering.
- Add cutoff and truthy-runtime regression coverage, plus
experimental-settings UI states that explain armed and suppressed
execution.

## Verification

- `pnpm exec vitest run server/src/__tests__/routines-service.test.ts
server/src/__tests__/instance-settings-service.test.ts` — passes: 2
files, 60 tests.
- `pnpm --filter @paperclipai/server typecheck` — passes.
- Existing CI completed successfully before the follow-up review fixes;
this branch was rebased onto the latest `origin/master` before
retesting.

## Risks

- **Behavioral:** Automatic worktree execution is intentionally more
restrictive; pre-existing work is suppressed until newly created after
activation.
- **Operational:** A malformed or cross-instance activation record fails
closed, requiring an operator to disable and re-enable the experimental
toggle on the intended worktree.
- **Compatibility:** The worktree environment now accepts all canonical
truthy values (`1`, `true`, `yes`, and `on`) consistently; non-worktree
instances are unaffected.
- **Branch metadata:** This existing execution-workspace branch predates
the current naming rule and cannot be renamed under this task's
workspace contract; the code and PR title do not include internal ticket
references.

> `ROADMAP.md` was checked; this targeted execution-safety fix does not
duplicate planned core work.

## Model Used

- Anthropic Claude Code — assisted with the original implementation;
exact model identifier and context window were not recorded in the
repository metadata.
- OpenAI Codex CLI — assisted with PR preparation and review fixes;
exact model identifier and context window are not exposed in this
execution environment. Used with terminal tooling, code editing, and
targeted 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)
- [ ] 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
- [ ] All Paperclip CI gates are green
- [ ] 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>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 16:11:26 -05:00
b13eb5b2b5 Skill Studio: three-pane skill IDE with sandboxed test runs (#9241)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Skills Manager gives operators a reusable skill layer, but
iteration still required manual edits, ad hoc prompts, and indirect run
inspection.
> - Skill authors need a focused workflow for editing skill files,
saving representative test inputs, and running those inputs through an
agent without exposing harness tasks as normal company work.
> - The backend therefore needs durable test inputs, reusable run
templates, hidden harness issues, scoped run execution, retention
metadata, and read-containment rules around hidden work.
> - The frontend needs a three-pane Studio that keeps skill files, saved
inputs/templates, and run output/history visible together while
preserving the existing design system and token rules.
> - This pull request ships that Skill Studio surface end to end:
database migrations, shared contracts, server APIs/services, hidden
harness execution behavior, UI routes/components, and focused tests.
> - The benefit is faster and safer skill iteration, with inspectable
outputs and fewer ways for internal harness work to leak into normal
task lists, costs, or adjacent read APIs.

## Linked Issues or Issue Description

No public GitHub issue exists for this feature. Feature request summary:

- Problem: Skill authors need to edit and test company skills in one
place instead of switching between the skill detail page, task creation,
run output, and manual prompt history.
- Proposed solution: Add a Skill Studio workbench with saved inputs,
reusable templates, hidden sandboxed test runs, live run status, output
inspection, run history, rerun/delete controls, and frontmatter-aware
editing.
- Expected users: Paperclip operators and agent-company maintainers who
create, fork, import, and tune skills.
- Related public PRs: Supersedes #9205, which was replaced so the public
PR branch name follows contributor policy.
- Duplicate search: searched public GitHub issues and PRs for "Skill
Studio"; no other active public issue or PR directly covers this
feature.

## What Changed

- Added database migrations for Skill Studio test inputs, test runs,
test run retention, and reusable run templates.
- Added shared Skill Studio types, validators, route helpers,
frontmatter utilities, and status handling.
- Added server services and routes for saved inputs, test runs,
templates, reruns, terminal-run deletion, hidden harness issue
execution, and run-detail hydration.
- Strengthened hidden-issue read containment across issue-adjacent
routes and cost rollups used by skill test harness work.
- Added the Skill Studio UI with skill file editing, frontmatter
editing, saved inputs, templates, run creation/cancel/rerun/delete
flows, output rendering, history, route support, and responsive pane
behavior.
- Added focused backend, shared, and UI tests for the new APIs, routing
logic, editor/run behavior, hidden-issue containment, and migration
safety.
- Rebased onto current `master`, removed the generated lockfile diff
from the PR, and verified no workflow files are changed.

## Verification

- [x] `pnpm --filter @paperclipai/db check:migrations`
- [x] `pnpm check:token-gates`
- [x] `pnpm exec vitest run
server/src/__tests__/company-skills-service.test.ts
server/src/__tests__/company-skills-routes.test.ts
server/src/__tests__/company-skill-test-runs-service.test.ts
ui/src/lib/skill-studio.test.ts ui/src/pages/SkillStudio.test.tsx` — 5
files, 132 tests passed
- [x] Greptile review on the latest PR head
- [x] GitHub PR checks on the latest PR head

## Risks

- Medium risk because this is a broad feature touching database schema,
server orchestration, issue visibility, and a large UI surface.
- Hidden harness issue containment is security-sensitive; this PR
includes regression coverage for adjacent read paths and cost rollups.
- The new migrations are additive and use idempotent guards where
applicable, but deployed databases that previously tested draft
migration numbers should still be checked carefully.
- The UI depends on a new resizable panels package in `ui/package.json`;
the lockfile is intentionally left to repository automation.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5 coding agent with shell, git, and GitHub CLI tool
use. Earlier feature commits include assistance from other Paperclip
coding agents; this PR preparation, rebase, cleanup commit, and PR body
were completed by OpenAI Codex in a Paperclip worktree.

## 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>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 13:08:56 -05:00
DottaandPaperclip 555391fed7 fix: run restart recovery, workspace self-heal, quota-aware retries, failed-run metrics (#9183)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Agents run in heartbeat runs orchestrated by the server; run
lifecycle, retry scheduling, and the dashboard's run-activity metrics
are the subsystems involved
> - A spike in "failed" tasks traced to three causes: server restarts
killing in-flight runs and mislabeling them as failures, deterministic
workspace-validation loops when a worktree's branch diverged, and
provider quota/usage-limit errors being classified as generic transient
failures (putting agents into error state and polluting metrics)
> - Killed-then-recovered runs and quota waits are not product failures,
so both the runtime behavior and the reporting needed to distinguish
them
> - This pull request drains runs gracefully on shutdown with idempotent
restart retries, self-heals workspace branch mismatches, adds a
quota-aware failure class with reset-time retry, separates recovered
restart kills from true failures on the dashboard, and documents restart
hygiene for operators
> - The benefit is fewer spurious failures, automatic recovery instead
of manual repair, and dashboard metrics that reflect real failure rates

## Linked Issues or Issue Description

No public GitHub issue exists; describing the bug inline per the
bug-report template:

**What happened?**

In-flight heartbeat runs are marked `failed` when the server restarts,
even though a retry later succeeds. Worktrees whose checked-out branch
diverges from the issue branch fail workspace validation on every
subsequent run with no recovery path. Provider quota/usage-limit
responses are treated as generic transient upstream errors, putting
agents into an error state and retrying before the quota window resets.
The dashboard counts all of these as true failures, inflating failure
metrics.

**Expected behavior**

Graceful shutdown should interrupt (not fail) running runs and chain
exactly one recovery retry. Workspace validation should repair
recoverable branch mismatches automatically. Quota errors should get
their own error class with the retry scheduled at the provider reset
time and the agent left idle. The dashboard should report recovered
restart kills separately from true failures.

**Steps to reproduce**

1. Start a heartbeat run, then restart the server (SIGTERM) while it is
in flight — the run lands as `failed` with a process-loss error code
even when its retry succeeds
2. Check out an issue whose worktree branch has diverged (e.g. after a
force-moved branch) — every subsequent run fails
`workspace_validation_failed` deterministically
3. Drive an agent into a provider usage-limit window — the run fails as
a generic transient upstream error and the agent enters an error state
instead of idling until the reset time

**Paperclip version or commit**

master (base c07e650cd)

**Deployment mode**

Self-hosted dev plane (Linux, node server + embedded Postgres)

## What Changed

- Graceful shutdown (SIGTERM hook) now marks in-flight runs
`interrupted` instead of `failed` and enqueues an idempotent
process-loss retry (pre-insert existence check on `retryOfRunId`
prevents duplicates; bursts chain exactly one retry per interrupted run)
- Run-liveness classification routes `interrupted` to `needs_followup`
rather than `failed`
- Workspace validation self-heals branch mismatch / missing-branch
states instead of failing deterministically on every run
- New `provider_quota` error class: session/usage-limit responses
schedule the retry at the provider reset time and leave the agent idle
(not errored); fixes a case where a quota-terminated run with subtype
`success` was misclassified as failed; HTTP 529 remains transient
- Dashboard run-activity query separates recovered restart kills from
true failures via a recursive CTE over `retry_of_run_id` (ancestors of a
succeeded retry count as recovered), adds a per-day failed-by-error-code
breakdown, and binds the window start as a timestamptz string
- Activity charts UI: amber "Recovered" segment with legend and per-day
error-code tooltip; success-rate chart counts recovered runs as
successes
- New ops runbook: `docs/deploy/dev-plane-restart-hygiene.md`

## Verification

- Greptile follow-up fixes on `992705edd`: `pnpm exec vitest run
server/src/__tests__/server-startup-feedback-export.test.ts
server/src/__tests__/heartbeat-workspace-branch-containment.test.ts
server/src/__tests__/heartbeat-workspace-session.test.ts
server/src/__tests__/heartbeat-process-recovery.test.ts
server/src/__tests__/heartbeat-workspace-finalize-branch.test.ts` (209
tests); `pnpm --filter @paperclipai/server typecheck`; `git diff
--check`
- Post-rebase CI fixes: `pnpm exec vitest run
server/src/__tests__/heartbeat-retry-scheduling.test.ts`; `pnpm exec
vitest run server/src/__tests__/heartbeat-retry-scheduling.test.ts
server/src/__tests__/workspace-runtime.test.ts
server/src/__tests__/heartbeat-workspace-branch-containment.test.ts
server/src/__tests__/heartbeat-workspace-finalize-branch.test.ts
server/src/__tests__/heartbeat-workspace-session.test.ts` (227 tests);
`pnpm --filter @paperclipai/server typecheck`
- `npm test` server suites covering the changes:
`heartbeat-process-recovery`, `heartbeat-stop-metadata`,
`heartbeat-retry-scheduling` (95 tests), quota parse +
execute/retry-scheduling suites (100 tests), workspace self-heal suites
(200 tests), dashboard run-activity tests (3 tests) — all green,
typecheck exit 0
- Dashboard CTE cross-checked against a real development database: two
restart-burst days moved from 17 to 8 and 19 to 6 true failures once
recovered kills were separated, matching manual retry-chain inspection
- Screenshot verification of the real ActivityCharts component
(recovered segment + tooltip) during QA

## Risks

- Behavioral shift: runs killed by a restart no longer surface as
`failed`; anyone consuming raw run statuses will see `interrupted` (new
status value) — dashboards/queries in this repo were updated accordingly
- Retry chaining on repeated restarts is bounded (one chained retry per
interruption) but a pathological restart loop still delays work rather
than failing it; the runbook covers operator hygiene for that case
- Dashboard query adds a recursive CTE; cost is bounded by the
day-window row count and was verified against production-sized data
- No schema migrations; low migration risk

## Model Used

- Claude (Anthropic) — claude-fable-5 via Claude Code / Paperclip agent
harness, extended thinking with tool use; implementation commits also
produced with Codex CLI (GPT-5 class) agents under the same harness

## 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)
- [ ] 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-07-07 20:30:09 -05:00
DottaandPaperclip 19454ce385 Deduplicate open watchdog review wakes (#9148)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Watchdogs keep issue execution moving by waking agents or creating
recovery paths when work stalls.
> - Open review states should generate useful follow-up, not repeated
duplicate wake requests for the same unresolved review condition.
> - Duplicate wakes create noise and can make the control plane look
busier without increasing progress.
> - This pull request deduplicates open watchdog review wake scheduling
and covers the behavior with scheduler tests.
> - The benefit is cleaner review wake behavior and fewer redundant
agent runs.

## Linked Issues or Issue Description

No public GitHub issue exists. Inline bug report:

**Pre-submission checklist**

- [x] I have searched existing open and closed issues and this is not a
duplicate.
- [x] I am on the latest released version of Paperclip (or can reproduce
on `master`).
- [x] I have confirmed the error originates in Paperclip itself — not in
my agent adapter, API provider, or local configuration.

**What happened?**

Watchdog scheduling could enqueue duplicate open review wake requests
while the same unresolved review condition was already pending.

**Expected behavior**

A watchdog should avoid scheduling redundant review wakes for the same
unresolved condition while preserving legitimate wake paths.

**Steps to reproduce**

1. Create an issue state that requires an open watchdog review wake.
2. Run the watchdog scheduler once and observe a wake request.
3. Run the scheduler again before resolving the original review
condition.
4. Observe whether a duplicate wake is created.

**Paperclip version or commit**

`master` at the PR base.

**Deployment mode**

Local dev (`pnpm dev`) and server deployments running watchdog
scheduling.

**Installation method**

Built from source (`pnpm dev` / `pnpm build`).

**Agent adapter(s) involved**

- [x] Not adapter-specific (core bug)

**Database mode**

Not database-related beyond scheduler persistence.

**Access context**

Agent wake scheduling and board-visible review state.

**Relevant logs or output**

Covered by the added scheduler regression test.

**Relevant config (if applicable)**

Not applicable.

**Additional context**

This suppresses duplicate wake scheduling only while the open review
state is still unresolved.

**Privacy checklist**

- [x] I have reviewed all pasted output for PII (usernames, file paths,
API keys, tokens, company names) and redacted where necessary.

## What Changed

- Added deduplication logic for open watchdog review wake scheduling.
- Added scheduler regression coverage for duplicate open review wake
suppression.

## Verification

- `/srv/paperclip/home/paperclipai/paperclip/node_modules/.bin/vitest
run server/src/__tests__/task-watchdogs-scheduler.test.ts`

## Risks

Low-to-medium risk. The change intentionally suppresses duplicate wake
scheduling, so reviewers should confirm no legitimate repeated wake path
depends on creating multiple open requests for the same unresolved
review state.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5.5 coding agent with repository tool use and local
shell execution. Context window was not surfaced by the runtime.

## 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-07 05:54:23 -05:00
a71c4b6782 [codex] feat(watchdog): add task watchdog control plane (#8339)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The task lifecycle and recovery subsystems decide when agent work is
still productive, stalled, or ready for review.
> - Existing recovery paths can observe stopped or incomplete work, but
there was no first-class per-task watchdog model with scoped review
permissions.
> - Watchdog follow-ups also need strict boundaries so
recovery/status-only runs cannot mutate approvals or perform deliverable
work.
> - This pull request adds the task watchdog data model, API/service
layer, scheduler/review flow, adapter wake context, UI configuration
surfaces, and docs.
> - The branch has been rebased onto current `paperclipai/paperclip`
`master`; the watchdog migration is now ordered after master's latest
migrations as `0104_issue_watchdogs`.
> - The benefit is a more explicit task-review loop that preserves
Paperclip's single-assignee and governance invariants while making
stalled work easier to route.

## Linked Issues or Issue Description

No linked GitHub issue. Paperclip task:
[PAP-11275](/PAP/issues/PAP-11275).

## Problem or motivation

Task recovery needs a first-class watchdog path that can inspect stopped
work and create scoped follow-ups without bypassing normal task
ownership. Board/UI users need a way to configure watchdogs on tasks and
see watchdog-related live work. Recovery/status-only runs must remain
limited to status reporting and must not create approvals, link
approvals, or submit approval comments.

## Proposed solution

Add a task-watchdog data model, scheduler/classifier, scoped mutation
guard, adapter wake context, API/UI configuration surfaces, and
documentation so watchdog agents can review stopped task subtrees under
explicit boundaries.

## Alternatives considered

Reuse the existing recovery-action flow only. That would keep
stopped-work detection implicit, make per-task watchdog assignment
harder to expose in the UI, and would not provide a durable
scoped-review issue for stalled task trees.

## Roadmap alignment

This is Paperclip control-plane lifecycle infrastructure for task
execution and recovery. I checked `ROADMAP.md`; this PR does not
duplicate an existing planned core item.

## What Changed

- Added issue watchdog schema, migration, shared contracts, validators,
CRUD API, and service support.
- Added task watchdog scheduler/classifier behavior, scoped mutation
enforcement, adapter wake context, and default watchdog mandate
guidance.
- Added UI surfaces for configuring watchdogs on new/existing tasks,
viewing watchdog activity, and exposing the experimental setting.
- Added docs for the user-facing task watchdog workflow and
implementation semantics.
- Gated new-task watchdog setup behind `enableTaskWatchdogs` and blocked
cheap status-only recovery runs from approval mutations.
- Rebased onto current `master` and renumbered the idempotent watchdog
migration from the branch-local `0102_issue_watchdogs` slot to
`0104_issue_watchdogs`.
- Addressed Greptile feedback by loading watchdog classifier input with
a recursive subtree query and centralizing the watchdog origin-kind
constant.
- Added and updated focused server/UI tests for watchdog routes,
scheduler/classifier behavior, scope boundaries, live task visibility,
settings, and new issue dialog behavior.

## Verification

- `pnpm vitest run server/src/__tests__/task-watchdogs-scheduler.test.ts
server/src/__tests__/task-watchdogs-classifier.test.ts`
- `pnpm vitest run
server/src/__tests__/approval-routes-idempotency.test.ts
server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts`
- `pnpm vitest run ui/src/components/NewIssueDialog.test.tsx`
- `pnpm --filter @paperclipai/server typecheck`
- `git diff --check`
- Verified the PR diff does not include `pnpm-lock.yaml` or
`.github/workflows`.

## Risks

- Medium risk: this introduces a new task lifecycle surface touching DB
schema, server routes/services, adapter wake context, and UI task
configuration.
- Watchdog scheduling behavior depends on the new experimental setting
and runtime context checks behaving consistently across local and
production agents.
- The watchdog migration is idempotent (`IF NOT EXISTS` /
duplicate-object guards) so users who tried the previous branch-local
migration number should not get duplicate-object failures.
- CI and the second Greptile pass are pending after the latest
review-fix push.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

OpenAI Codex, GPT-5-class coding agent in the Paperclip workspace. Exact
runtime model id and context window were not exposed to the agent; tool
use and local command execution were enabled.

## 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots — N/A per Paperclip task instruction: do not add
screenshots/images to this PR unless they are specifically part of the
work.
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] 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>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 15:38:52 -05:00