Backfill projected shell summaries and stale approval cleanup#2004
Backfill projected shell summaries and stale approval cleanup#2004juliusmarminge merged 4 commits intomainfrom
Conversation
- Recompute projected thread shell counts during migration - Treat stale pending approval failures as resolved in projection - Add coverage for the backfill and projection behavior
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Stale failure handler overwrites already-resolved approval decisions
- Added an early return for
existingRow.value.status === "resolved"in the stale failure code path in ProjectionPipeline.ts, and addedAND status = 'pending'to the migration's stale failure UPDATE WHERE clause, preventing both from overwriting already-resolved approval decisions.
- Added an early return for
- ✅ Fixed: Migration count ignores its own event-store resolutions
- Replaced the activity-based
pending_approval_countsubquery in migration step 5 withSELECT COUNT(*) FROM projection_pending_approvals WHERE status = 'pending', matching the runtime'srefreshThreadShellSummarybehavior and correctly reflecting resolutions applied by earlier migration steps.
- Replaced the activity-based
Or push these changes by commenting:
@cursor push 25f8053d3b
Preview (25f8053d3b)
diff --git a/apps/server/src/orchestration/Layers/ProjectionPipeline.ts b/apps/server/src/orchestration/Layers/ProjectionPipeline.ts
--- a/apps/server/src/orchestration/Layers/ProjectionPipeline.ts
+++ b/apps/server/src/orchestration/Layers/ProjectionPipeline.ts
@@ -1268,6 +1268,9 @@
if (Option.isNone(existingRow)) {
return;
}
+ if (existingRow.value.status === "resolved") {
+ return;
+ }
yield* projectionPendingApprovalRepository.upsert({
requestId,
threadId: existingRow.value.threadId,
diff --git a/apps/server/src/persistence/Migrations/024_BackfillProjectionThreadShellSummary.ts b/apps/server/src/persistence/Migrations/024_BackfillProjectionThreadShellSummary.ts
--- a/apps/server/src/persistence/Migrations/024_BackfillProjectionThreadShellSummary.ts
+++ b/apps/server/src/persistence/Migrations/024_BackfillProjectionThreadShellSummary.ts
@@ -175,11 +175,12 @@
FROM latest_stale_failures
WHERE latest_stale_failures.request_id = projection_pending_approvals.request_id
)
- WHERE EXISTS (
- SELECT 1
- FROM latest_stale_failures
- WHERE latest_stale_failures.request_id = projection_pending_approvals.request_id
- )
+ WHERE status = 'pending'
+ AND EXISTS (
+ SELECT 1
+ FROM latest_stale_failures
+ WHERE latest_stale_failures.request_id = projection_pending_approvals.request_id
+ )
`;
yield* sql`
@@ -192,40 +193,10 @@
AND message.role = 'user'
),
pending_approval_count = COALESCE((
- WITH latest_approval_states AS (
- SELECT
- latest.request_id,
- latest.kind,
- latest.detail
- FROM (
- SELECT
- json_extract(activity.payload_json, '$.requestId') AS request_id,
- activity.kind,
- lower(COALESCE(json_extract(activity.payload_json, '$.detail'), '')) AS detail,
- ROW_NUMBER() OVER (
- PARTITION BY json_extract(activity.payload_json, '$.requestId')
- ORDER BY activity.created_at DESC, activity.activity_id DESC
- ) AS row_number
- FROM projection_thread_activities AS activity
- WHERE activity.thread_id = projection_threads.thread_id
- AND json_extract(activity.payload_json, '$.requestId') IS NOT NULL
- AND activity.kind IN (
- 'approval.requested',
- 'approval.resolved',
- 'provider.approval.respond.failed'
- )
- ) AS latest
- WHERE latest.row_number = 1
- )
SELECT COUNT(*)
- FROM latest_approval_states
- WHERE latest_approval_states.kind = 'approval.requested'
- OR (
- latest_approval_states.kind = 'provider.approval.respond.failed'
- AND latest_approval_states.detail NOT LIKE '%stale pending approval request%'
- AND latest_approval_states.detail NOT LIKE '%unknown pending approval request%'
- AND latest_approval_states.detail NOT LIKE '%unknown pending permission request%'
- )
+ FROM projection_pending_approvals
+ WHERE projection_pending_approvals.thread_id = projection_threads.thread_id
+ AND projection_pending_approvals.status = 'pending'
), 0),
pending_user_input_count = COALESCE((
WITH latest_user_input_states AS (You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit b6bcd14. Configure here.
apps/server/src/persistence/Migrations/024_BackfillProjectionThreadShellSummary.ts
Show resolved
Hide resolved
ApprovabilityVerdict: Needs human review This PR modifies runtime behavior in the approval system by automatically resolving pending approvals when stale/unknown failure events occur, and includes a data migration that backfills existing records. While the changes are well-tested, they affect how the approval workflow operates and warrant human review. No code changes detected at You can customize Macroscope's approvability policy. Learn more. |
…n pending count - ProjectionPipeline: add early return when existingRow is already resolved in the stale failure code path, preventing decision from being overwritten with null on already-resolved approvals. - Migration step 4: add AND status = 'pending' condition so stale failure backfill does not overwrite rows already resolved by earlier steps. - Migration step 5: replace activity-based pending_approval_count derivation with a direct count from projection_pending_approvals WHERE status = 'pending', consistent with the runtime's refreshThreadShellSummary. Applied via @cursor push command
- Keep `provider.approval.respond.failed` events from clearing current pending approvals when they do not match the active request - Add regression coverage for existing and missing approval rows


Summary
projection_threadsshell summary fields from existing thread activity, messages, pending approvals, and proposed plans.provider.approval.respond.failedevents with unknown/stale request details.Testing
apps/server/src/persistence/Migrations/024_BackfillProjectionThreadShellSummary.test.ts.apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts.bun fmtbun lintbun typecheckbun run testNote
Medium Risk
Adds a data backfill migration and changes pending-approval projection behavior to auto-resolve certain failure cases; mistakes could incorrectly clear approvals or produce wrong thread summary counts.
Overview
Adds migration
024_BackfillProjectionThreadShellSummaryto backfillprojection_threadsshell summary fields (latest_user_message_at,pending_approval_count,pending_user_input_count,has_actionable_proposed_plan) from existing messages/activities/proposed plans, and to seed/updateprojection_pending_approvalsbased on historicapproval.requested/approval.resolvedactivity andthread.approval-response-requestedevents.Updates the projection pipeline so
provider.approval.respond.failedactivities whosedetailindicates an unknown/stale pending approval now resolve the existing pending approval (droppingpending_approval_countaccordingly), and adds focused tests covering both stale and non-stale failure paths plus the migration backfill behavior.Reviewed by Cursor Bugbot for commit 232001d. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Backfill projected thread shell summaries and resolve stale pending approvals in migration 24
projection_threadsshell summary fields (latest_user_message_at,pending_approval_count,pending_user_input_count,has_actionable_proposed_plan) and seeds/resolvesprojection_pending_approvalsrows from existing activity history.provider.approval.respond.failedactivities whosedetailindicates an unknown or stale permission request, settingresolved_atto the failure activity's timestamp.isStalePendingApprovalFailureDetailhelper in ProjectionPipeline.ts and a matching projection branch so the same stale-approval resolution logic applies to newly projected activities going forward.provider.approval.respond.failedactivities with stale/unknown detail strings now resolve the corresponding pending approval row rather than being ignored.Macroscope summarized 232001d.