mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-30 13:20:54 +01:00
fix(server): schedule approval retention from durable source deadlines
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
f240381fd8
commit
ea3dd40cdd
27 files changed
+893
-150
No files matched your search
@@ -0,0 +1,93 @@
|
||||
# Approval retention without idle polling
|
||||
|
||||
This slice removes approval retention from the recurring attention-feed sweep.
|
||||
It does not migrate the other attention source kinds or establish host sleep.
|
||||
|
||||
## Obligation and owner
|
||||
|
||||
A pending approval in an active company is eligible for automatic archiving
|
||||
90 days after its last approval activity, unless kept or already archived.
|
||||
This is a presentation/attention archive: it does not approve, reject, cancel,
|
||||
or delete the approval. The deadline and policy are unchanged.
|
||||
|
||||
Approval rows are the source of truth, including those never viewed in the
|
||||
attention UI. Scheduling only existing `decision_retention` rows would miss
|
||||
unseen approvals because the old feed reader materializes those rows lazily.
|
||||
`approval-retention.ts` discovers eligible approvals directly and registers
|
||||
the earliest actual deadline with the existing delivery coordinator.
|
||||
|
||||
The query retains the attention feed's first-linked-issue rule and consumes
|
||||
`executionIssueCondition` from the issue visibility owner. Hidden, harness and
|
||||
agent-conversation tasks remain excluded. A waiting external conversation with
|
||||
a linked pending approval is active under that same shared visibility policy;
|
||||
its chat state alone cannot hide this approval. Tests exercise the Slack case.
|
||||
|
||||
Each pass visits at most 100 candidates in activity/id order. A failed row does
|
||||
not prevent later pages from progressing. The failed durable record remains
|
||||
eligible for recovery. Each candidate is re-read and locked before archiving,
|
||||
so a resubmission committed while the worker waited cannot archive the new
|
||||
activity using an old selection. Existing retention version, keep and archive
|
||||
compare-and-set checks remain authoritative. This does not add cross-table
|
||||
serializability for concurrent link/visibility/company policy changes.
|
||||
|
||||
## Producer coverage
|
||||
|
||||
| Supported producer | Notification boundary |
|
||||
| --- | --- |
|
||||
| Approval create, cancel, revision, resubmit | SQL write transaction in approval records |
|
||||
| Approval resolution, including hire lifecycle | SQL write, retaining the caller's outer transaction |
|
||||
| Hard budget approval and budget resolution | Existing accounting transaction |
|
||||
| Formal tool approval and issue link | SQL write transaction; provider work is outside it |
|
||||
| Link, unlink and bulk link | Issue approval write transaction |
|
||||
| Issue visibility changes and deletion | Existing issue mutation transaction |
|
||||
| Routine creation rollback cleanup | Existing transaction before cascading issue deletion |
|
||||
| Company activation, pause, archive and deletion | Existing company/accounting transaction |
|
||||
| Keep, manual archive, revive and accepted archive manifest | Existing retention mutation transaction |
|
||||
| Retention materialization or source activity change | Signal only when inserting or changing actual state |
|
||||
|
||||
Approval comments do not change approval activity under the existing policy.
|
||||
Company portability imports do not write approvals; restored durable records
|
||||
are reconstructed at startup. Signals belong to the application DB owner and
|
||||
its dedicated child pools. Independent SQL writers or another active process
|
||||
need explicit integration; this change does not claim to observe them.
|
||||
|
||||
## Shared contracts and lifecycle
|
||||
|
||||
The main maintenance feed excludes the approval source before collecting it.
|
||||
Public attention reads keep their existing default behavior. Other attention
|
||||
sources remain in the aggregate sweep until separately migrated.
|
||||
|
||||
The retention service accepts the source fields it actually uses rather than
|
||||
requiring fabricated full UI attention items. Its existing versioned state,
|
||||
audit writes, authorization and archive-notification outbox are reused. No new
|
||||
queue table is introduced. Transaction-aware notifications retain intent until
|
||||
the outer transaction settles, including nested writes and rollback.
|
||||
|
||||
The deadline worker uses the shared scheduler's generation and drain behavior.
|
||||
Startup reconstructs pending work; idle drain retains requests without passive
|
||||
SQL; resume reconciles them. Failed work retains a 30-second recovery spacing.
|
||||
No eligible approval means no recurring deadline or query. Completed history,
|
||||
kept/archived approvals, and inactive companies are quiet until a supported
|
||||
mutation changes eligibility. Shutdown joins admitted work and stops between
|
||||
candidates. Notification delivery remains owned by the separate archive worker.
|
||||
|
||||
A pending-only `(updated_at, id)` index bounds deadline lookup independently of
|
||||
resolved approval history. The migration uses concurrent, idempotent creation
|
||||
and the existing migration runner's nontransactional execution list.
|
||||
|
||||
## Verification and limits
|
||||
|
||||
Real-Postgres lifecycle tests cover unseen sources, future deadlines, retained
|
||||
history, keep/unkeep, archive/revive, revision/resubmission, company activity,
|
||||
linked issue visibility/deletion/order, normal versus maintenance attention
|
||||
reads, nested commits/rollback, startup and first-write drain, failed database
|
||||
writes through drain, bounded progress past failure, shutdown, and a concurrent
|
||||
resubmission. The waiting-Slack case also checks durable notification creation.
|
||||
|
||||
Existing approval, attention, retention, budget, tool-gateway and startup suites
|
||||
are relevant consumers. Track final results and any failures in the PR and the
|
||||
[stack ledger](plans/2026-10-24-recurring-server-sleep-stack.md).
|
||||
|
||||
The Cloud sleep guards are unchanged. An in-process deadline cannot wake stopped
|
||||
compute, and this approval deadline has not been added to Cloud's durable wake
|
||||
contract. This proves only the named worker's quiet/reactivation behavior.
|
||||
@@ -15,8 +15,8 @@ Do not mark an item done from a timer removal or a green check alone.
|
||||
| 01 | Custom-image setup expiry | Session writes, existing expiry, startup/retry/drain | [#17443](https://github.com/paperclipai/paperclip/pull/17443), all checks passed, Greptile 5/5 at `36844a458b` |
|
||||
| 02 | Remaining chat maintenance | Provider runtime discovery; voice reconciliation; milestones; wake notices; interaction continuations; terminal confirmations; GitHub recovery; Teams maintenance, separately by owner | Pending |
|
||||
| 03 | Run and task recovery | Orphan runs and active leases; shutdown workspace settlement; scheduled retries; queued runs; stranded assignments; resolved dependencies; task watchdogs; silent-run monitoring; stale locks | Pending |
|
||||
| 04 | Decision retention and notifications | Retention deadlines and notification delivery are separate reasons | Retention pending; notification delivery: [#17475](https://github.com/paperclipai/paperclip/pull/17475), all checks passed (Paperclip Review skipped), Greptile 5/5 at `692e3ee02c` |
|
||||
| 05 | Decision expiry and interrupted effects | Expiry, effect recovery, continuation recovery | Continuations: [#17478](https://github.com/paperclipai/paperclip/pull/17478), all checks passed, Greptile 5/5 at `5f96892a58`; TTL: [#17479](https://github.com/paperclipai/paperclip/pull/17479), all checks passed, Greptile 5/5 at `63b58cc26f`; effects: [#17482](https://github.com/paperclipai/paperclip/pull/17482), local verification passed at `a5b5994c1d`, CI/review running; target invalidation pending |
|
||||
| 04 | Decision retention and notifications | Retention deadlines and notification delivery are separate reasons | Approval retention implemented in slice 14, verification in progress; other source owners pending; notification delivery: [#17475](https://github.com/paperclipai/paperclip/pull/17475), all checks passed (Paperclip Review skipped), Greptile 5/5 at `692e3ee02c` |
|
||||
| 05 | Decision expiry and interrupted effects | Expiry, effect recovery, continuation recovery | Continuations: [#17478](https://github.com/paperclipai/paperclip/pull/17478), all checks passed, Greptile 5/5 at `5f96892a58`; TTL: [#17479](https://github.com/paperclipai/paperclip/pull/17479), all checks passed, Greptile 5/5 at `63b58cc26f`; effects: [#17482](https://github.com/paperclipai/paperclip/pull/17482), all checks passed, Greptile 5/5 at `a5b5994c1d`; target invalidation: [#17486](https://github.com/paperclipai/paperclip/pull/17486), all checks passed, Greptile 5/5 at `1bbfc69590` |
|
||||
| 06 | Tool connection health | Configuration/use activation and defined proactive health deadlines | Pending |
|
||||
| 07 | Secret proposals, tool reviews, gateway tokens | Separate expiry/scrub/recovery owners | Secret proposals: [#17446](https://github.com/paperclipai/paperclip/pull/17446), checks passed at `d41590ac0e`; gateway credentials: [#17450](https://github.com/paperclipai/paperclip/pull/17450), all checks passed, Greptile 5/5 at `c5c53fc43f`; pending tool-review expiry: [#17453](https://github.com/paperclipai/paperclip/pull/17453), all checks passed, Greptile 5/5 at `ce6a260a83`; approved recovery: [#17454](https://github.com/paperclipai/paperclip/pull/17454), all checks passed, Greptile 5/5 at `7a1cf03e62`; interrupted claims: [#17458](https://github.com/paperclipai/paperclip/pull/17458), all checks passed, Greptile 5/5 at `85003a7ac4`; projection: [#17468](https://github.com/paperclipai/paperclip/pull/17468), all checks passed, Greptile 5/5 at `0956883a84` |
|
||||
| 08 | GitHub connection events and continuity | Event discovery/replay and credential continuity separately | Pending |
|
||||
@@ -28,7 +28,8 @@ Do not mark an item done from a timer removal or a green check alone.
|
||||
| 14 | Skill-version retention and native-harness backup expiration | Separate retention owners and existing retention guarantees | Pending |
|
||||
| 15 | Automatic database backups | Shared scheduling, actual backup deadlines, existing checkpoint contract | Pending |
|
||||
| 16 | Aggregate maintenance tick | Retire enabled and disabled branches after all constituent owners migrate | Pending |
|
||||
| 17 | Grok routine dispatch | Committed reservations and feature changes; prepared-only recovery | Slice 13 implemented, local verification in progress |
|
||||
| 17 | Grok routine dispatch | Committed reservations and feature changes; prepared-only recovery | [#17490](https://github.com/paperclipai/paperclip/pull/17490), all checks passed, Greptile 5/5 at `706beb01f2` |
|
||||
| 18 | Abandoned import transfer spools | Creation/completion events, existing retention deadline, startup recovery | Pending; explicitly retained from the remaining-blocker checklist |
|
||||
|
||||
## Stack and verification contract
|
||||
|
||||
@@ -730,3 +731,58 @@ at this snapshot). These are verified live waits, not completed checks. Do not
|
||||
rerun them merely because a later observation times out. Continue inspecting
|
||||
these runs while implementing retention, and propagate any required parent
|
||||
repair into the later branch. No stack PR was merged.
|
||||
|
||||
|
||||
## Approval retention implementation in progress
|
||||
|
||||
Remote verification on October 24: #17486 at `1bbfc69590` and #17490 at
|
||||
`706beb01f2` each have 56 completed checks, all successful or accepted
|
||||
neutral/skipped outcomes. Their PR bodies now record completion. Neither was
|
||||
merged; this remains a stack.
|
||||
|
||||
The retention audit is now split by source owner. Slice 14 migrates **approval
|
||||
retention only**. Decisions, interactions, join requests, recovery actions,
|
||||
blocker attention, review, failed runs, budget alerts and agent errors remain
|
||||
explicitly pending. The original full recurring-work inventory remains scope.
|
||||
|
||||
The implementation discovers pending approvals directly, including approvals
|
||||
never materialized by an attention-feed read. It uses active-company status,
|
||||
the feed's first linked issue, shared execution visibility, keep/archive state,
|
||||
and the approval's updated timestamp. The next obligation is updated timestamp
|
||||
plus 90 days. Each bounded pass rechecks and locks the approval before using
|
||||
existing versioned retention, audit and notification-outbox writes. Other
|
||||
retention sources still use the aggregate sweep; approval collection is excluded
|
||||
from that maintenance feed before its query, while normal UI reads are unchanged.
|
||||
|
||||
Signals cover approval create/cancel/revision/resubmit/resolve, hard budget
|
||||
approvals, formal tool approvals, link/unlink/bulk linking, issue visibility and
|
||||
cascading deletion, company activation/pause/archive/deletion, and keep/archive/
|
||||
revive/accepted archive manifests. Source comments do not alter approval activity
|
||||
under the existing policy. Company portability imports no approval records;
|
||||
offline restore is reconstructed at startup. Independent SQL writers still
|
||||
require a wake integration. The Cloud sleep proof is unchanged.
|
||||
|
||||
Initial real-Postgres proof: 14 lifecycle cases passed, then 19 including actual
|
||||
archive-write faults, page progress past a failed row, startup drain, first-link
|
||||
ordering and shutdown. The first consumer run passed retention and startup but
|
||||
failed five approval unit cases because its transaction stub omitted nested
|
||||
transactions; the stub was repaired without weakening production behavior.
|
||||
The budget suite initially skipped due to embedded-Postgres availability. Budget
|
||||
and attention suites now accept validated disposable external test databases.
|
||||
Expanded consumer verification, final index/migration proof, build and PR review
|
||||
remain required. No slice-14 PR has been published yet.
|
||||
|
||||
|
||||
Slice 14 expanded proof: all 20 worker lifecycle cases pass. The shared execution
|
||||
visibility predicate is used directly, and a waiting Slack conversation with a
|
||||
pending approval remains eligible with its archive notification persisted. The
|
||||
repaired approval stub and attention/retention/startup suites pass. Of 96 consumer
|
||||
cases, one budget case initially timed out during lazy lifecycle module loading
|
||||
and raced teardown; moving the import into setup preserves the original timeout
|
||||
and all five budget cases pass. No assertion or production behavior was weakened.
|
||||
The initial index diagnostic failed to construct a Drizzle client around the
|
||||
scoped raw driver; supplying its existing driver options fixed the diagnostic.
|
||||
The actual deadline query with 40,000 resolved approvals uses the pending index,
|
||||
four shared buffer hits and 0.314 ms execution; test data rolled back. Migration
|
||||
replay and checks pass. Workspace types, build and tool-gateway tests remain live
|
||||
in the current verification run. This is not final acceptance.
|
||||
Reference in new issue
Block a user