fix: optimize low-trust blocked count

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-06-05 19:19:38 +00:00
1 parent 9992e568ce
commit 2719f31e3f
4 files changed
+93 -1

No files matched your search

@@ -772,6 +772,41 @@ describeEmbeddedPostgres("low-trust red-team HTTP route regression suite", () =>
}
});
it("counts blocked inbox issues with the low-trust boundary applied in the database", async () => {
const fixture = await seedLowTrustFixture(db);
await db.insert(issues).values([
{
companyId: fixture.company.id,
projectId: fixture.projects.allowed.id,
parentId: fixture.issues.reviewRoot.id,
title: "Visible blocked vendor wait",
status: "blocked",
priority: "medium",
description: "external owner: Visible vendor\nexternal action: Finish visible review",
},
{
companyId: fixture.company.id,
projectId: fixture.projects.outOfScope.id,
title: "Hidden blocked vendor wait",
status: "blocked",
priority: "medium",
description: "external owner: Hidden vendor\nexternal action: Finish hidden review",
},
]);
const boardCount = await request(createApp(db, boardActor(fixture)))
.get(`/api/companies/${fixture.company.id}/issues/count`)
.query({ attention: "blocked", q: "blocked vendor wait" });
expect(boardCount.status, JSON.stringify(boardCount.body)).toBe(200);
expect(boardCount.body.count).toBe(2);
const lowTrustCount = await request(createApp(db, agentActor(fixture)))
.get(`/api/companies/${fixture.company.id}/issues/count`)
.query({ attention: "blocked", q: "blocked vendor wait" });
expect(lowTrustCount.status, JSON.stringify(lowTrustCount.body)).toBe(200);
expect(lowTrustCount.body.count).toBe(1);
});
it("redacts quarantined low-trust output from higher-trust wake and continuation contexts", async () => {
const fixture = await seedLowTrustFixture(db);
const lowTrustApp = createApp(db, agentActor(fixture));
+18
View File
@@ -2440,6 +2440,24 @@ export function issueRoutes(
} as const;
if (!(await actorCanReadCompanyScope(req, companyId))) {
const trustResolution = req.actor.type === "agent"
? await resolveAgentTrustForIssue({
agentId: req.actor.agentId,
runId: req.actor.runId,
}, companyId, null)
: null;
if (trustResolution?.kind === "denied") {
throw forbidden(trustResolution.detail);
}
if (trustResolution?.kind === "low_trust_review") {
const count = await svc.count(companyId, {
...blockedCountFilters,
lowTrustBoundary: trustResolution.boundary,
});
res.json({ count });
return;
}
let offset = 0;
let visibleCount = 0;
while (true) {
+1 -1
View File
@@ -7552,7 +7552,7 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {})
db,
companyId: agent.companyId,
contextSnapshot: context,
continuationSummary: safeContinuationSummary,
continuationSummary,
issueSummary: issueRef
? {
id: issueRef.id,
+39
View File
@@ -44,6 +44,7 @@ import type {
IssueProductivityReview,
IssueProductivityReviewTrigger,
IssueRelationIssueSummary,
LowTrustBoundary,
SuccessfulRunHandoffState,
} from "@paperclipai/shared";
import {
@@ -244,6 +245,7 @@ export interface IssueFilters {
includeBlockedBy?: boolean;
includeBlockedInboxAttention?: boolean;
hasPlanDocument?: boolean;
lowTrustBoundary?: LowTrustBoundary & { companyId: string };
q?: string;
limit?: number;
offset?: number;
@@ -1181,6 +1183,39 @@ const PRODUCTIVITY_REVIEW_TRIGGERS: readonly IssueProductivityReviewTrigger[] =
"long_active_duration",
"high_churn",
];
function lowTrustBoundaryIssueCondition(
companyId: string,
boundary: (LowTrustBoundary & { companyId: string }) | null | undefined,
) {
if (!boundary || boundary.companyId !== companyId) return null;
const clauses: SQL[] = [];
const issueIds = [...new Set(boundary.issueIds ?? [])];
const projectIds = [...new Set(boundary.projectIds ?? [])];
if (issueIds.length > 0) clauses.push(inArray(issues.id, issueIds));
if (projectIds.length > 0) clauses.push(inArray(issues.projectId, projectIds));
if (boundary.rootIssueId) {
clauses.push(sql<boolean>`
${issues.id} IN (
WITH RECURSIVE descendants(id) AS (
SELECT ${issues.id}
FROM ${issues}
WHERE ${issues.companyId} = ${companyId}
AND ${issues.id} = ${boundary.rootIssueId}
UNION
SELECT ${issues.id}
FROM ${issues}
JOIN descendants ON ${issues.parentId} = descendants.id
WHERE ${issues.companyId} = ${companyId}
)
SELECT id FROM descendants
)
`);
}
if (clauses.length === 0) return sql<boolean>`false`;
return or(...clauses);
}
const BLOCKER_ATTENTION_OPEN_RECOVERY_TERMINAL_STATUSES = ["done", "cancelled"];
const BLOCKER_ATTENTION_MAX_DEPTH = 8;
const BLOCKER_ATTENTION_MAX_NODES = 2000;
@@ -2874,6 +2909,8 @@ async function blockedInboxIssueConditions(
)
`);
}
const lowTrustCondition = lowTrustBoundaryIssueCondition(companyId, filters?.lowTrustBoundary);
if (lowTrustCondition) conditions.push(lowTrustCondition);
if (filters?.status) {
const statuses = filters.status.split(",").map((status) => status.trim()).filter(Boolean);
if (statuses.length > 0) {
@@ -3841,6 +3878,8 @@ export function issueService(db: Db) {
)
`);
}
const lowTrustCondition = lowTrustBoundaryIssueCondition(companyId, filters?.lowTrustBoundary);
if (lowTrustCondition) conditions.push(lowTrustCondition);
if (filters?.status) {
const statuses = filters.status.split(",").map((s) => s.trim());
conditions.push(statuses.length === 1 ? eq(issues.status, statuses[0]) : inArray(issues.status, statuses));