fix(team): hide review pickup escalation rows
This commit is contained in:
parent
fa829f92c8
commit
5d3ec8a8bd
5 changed files with 92 additions and 12 deletions
|
|
@ -287,29 +287,42 @@ function buildMemberWorkSyncReviewPickupEscalationText(input: {
|
||||||
}): string {
|
}): string {
|
||||||
const taskLines = input.taskRefs.length
|
const taskLines = input.taskRefs.length
|
||||||
? input.taskRefs
|
? input.taskRefs
|
||||||
.map(
|
.map((taskRef) => `- ${taskRef.displayId ?? taskRef.taskId.slice(0, 8)}`)
|
||||||
(taskRef) => `- ${taskRef.displayId ?? taskRef.taskId.slice(0, 8)} (${taskRef.taskId})`
|
|
||||||
)
|
|
||||||
.join('\n')
|
.join('\n')
|
||||||
: '- No task refs recorded';
|
: '- No task refs recorded';
|
||||||
const diagnostics = [...new Set(input.diagnostics ?? [])].filter(Boolean);
|
const reasonText = describeMemberWorkSyncReviewPickupEscalationReason(input.reason);
|
||||||
return [
|
return [
|
||||||
'Review pickup still pending in member work-sync.',
|
'Review pickup needs lead attention.',
|
||||||
'',
|
'',
|
||||||
`Reviewer: ${input.memberName}`,
|
`Reviewer: ${input.memberName}`,
|
||||||
`Reason: ${input.reason}`,
|
reasonText,
|
||||||
'',
|
'',
|
||||||
'Tasks:',
|
'Tasks:',
|
||||||
taskLines,
|
taskLines,
|
||||||
'',
|
'',
|
||||||
'No review_start, review_approve, or review_request_changes was recorded for the current review request after the member correction path.',
|
'No review_start, review_approve, or review_request_changes was recorded for the current review request.',
|
||||||
'Consider reassigning the reviewer or sending a direct instruction.',
|
'Consider reassigning the reviewer or sending a direct instruction.',
|
||||||
diagnostics.length ? `Diagnostics: ${diagnostics.join(', ')}` : '',
|
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function describeMemberWorkSyncReviewPickupEscalationReason(reason: string): string {
|
||||||
|
if (reason.startsWith('provider_not_supported:')) {
|
||||||
|
return 'Direct review-pickup wake is not available for this member runtime, so the lead needs to handle the stuck review.';
|
||||||
|
}
|
||||||
|
if (reason === 'review_pickup_already_delivered_still_stuck') {
|
||||||
|
return 'A review-pickup reminder was delivered, but the review is still waiting for a review tool action.';
|
||||||
|
}
|
||||||
|
if (reason === 'review_pickup_delivery_failed_still_stuck') {
|
||||||
|
return 'The review-pickup reminder could not be delivered reliably, and the review is still waiting.';
|
||||||
|
}
|
||||||
|
if (reason.includes('delivery_port_unavailable')) {
|
||||||
|
return 'No reliable review-pickup delivery path is available for this member runtime.';
|
||||||
|
}
|
||||||
|
return 'The current review request is still waiting for explicit review pickup.';
|
||||||
|
}
|
||||||
|
|
||||||
async function createOpenCodeRuntimeAdapterRegistry(
|
async function createOpenCodeRuntimeAdapterRegistry(
|
||||||
reportProgress: (phase: string, message: string) => void = () => undefined
|
reportProgress: (phase: string, message: string) => void = () => undefined
|
||||||
): Promise<TeamRuntimeAdapterRegistry> {
|
): Promise<TeamRuntimeAdapterRegistry> {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,10 @@ import { filterTeamMessages } from '@renderer/utils/teamMessageFiltering';
|
||||||
import { toMessageKey } from '@renderer/utils/teamMessageKey';
|
import { toMessageKey } from '@renderer/utils/teamMessageKey';
|
||||||
import { shouldExcludeInboxTextFromReplyCandidates } from '@shared/utils/idleNotificationSemantics';
|
import { shouldExcludeInboxTextFromReplyCandidates } from '@shared/utils/idleNotificationSemantics';
|
||||||
import { isLeadMember } from '@shared/utils/leadDetection';
|
import { isLeadMember } from '@shared/utils/leadDetection';
|
||||||
import { isTaskStallRemediationMessage } from '@shared/utils/teamAutomationMessages';
|
import {
|
||||||
|
isReviewPickupEscalationMessage,
|
||||||
|
isTaskStallRemediationMessage,
|
||||||
|
} from '@shared/utils/teamAutomationMessages';
|
||||||
import {
|
import {
|
||||||
CheckCheck,
|
CheckCheck,
|
||||||
ChevronsDownUp,
|
ChevronsDownUp,
|
||||||
|
|
@ -603,6 +606,7 @@ export const MessagesPanel = memo(function MessagesPanel({
|
||||||
(m) =>
|
(m) =>
|
||||||
m.messageKind !== 'task_comment_notification' &&
|
m.messageKind !== 'task_comment_notification' &&
|
||||||
!isTaskStallRemediationMessage(m) &&
|
!isTaskStallRemediationMessage(m) &&
|
||||||
|
!isReviewPickupEscalationMessage(m) &&
|
||||||
!shouldExcludeInboxTextFromReplyCandidates(typeof m.text === 'string' ? m.text : '')
|
!shouldExcludeInboxTextFromReplyCandidates(typeof m.text === 'string' ? m.text : '')
|
||||||
),
|
),
|
||||||
[effectiveMessages]
|
[effectiveMessages]
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ import {
|
||||||
} from '@renderer/utils/bootstrapPromptSanitizer';
|
} from '@renderer/utils/bootstrapPromptSanitizer';
|
||||||
import { shouldKeepIdleMessageInActivityWhenNoiseHidden } from '@renderer/utils/idleNotificationSemantics';
|
import { shouldKeepIdleMessageInActivityWhenNoiseHidden } from '@renderer/utils/idleNotificationSemantics';
|
||||||
import { isInboxNoiseMessage } from '@shared/utils/inboxNoise';
|
import { isInboxNoiseMessage } from '@shared/utils/inboxNoise';
|
||||||
import { isTaskStallRemediationMessage } from '@shared/utils/teamAutomationMessages';
|
import {
|
||||||
|
isReviewPickupEscalationMessage,
|
||||||
|
isTaskStallRemediationMessage,
|
||||||
|
} from '@shared/utils/teamAutomationMessages';
|
||||||
import { isTeamInternalControlMessageEnvelope } from '@shared/utils/teamInternalControlMessages';
|
import { isTeamInternalControlMessageEnvelope } from '@shared/utils/teamInternalControlMessages';
|
||||||
|
|
||||||
import type { InboxMessage } from '@shared/types';
|
import type { InboxMessage } from '@shared/types';
|
||||||
|
|
@ -133,6 +136,7 @@ export function filterTeamMessages(
|
||||||
(m) =>
|
(m) =>
|
||||||
m.messageKind !== 'task_comment_notification' &&
|
m.messageKind !== 'task_comment_notification' &&
|
||||||
(includeAutomationEvents || !isTaskStallRemediationMessage(m)) &&
|
(includeAutomationEvents || !isTaskStallRemediationMessage(m)) &&
|
||||||
|
!isReviewPickupEscalationMessage(m) &&
|
||||||
!isTeamInternalControlMessageEnvelope(m)
|
!isTeamInternalControlMessageEnvelope(m)
|
||||||
);
|
);
|
||||||
if (timeWindow) {
|
if (timeWindow) {
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,26 @@ import type { InboxMessage } from '@shared/types';
|
||||||
|
|
||||||
type AutomationMessageLike = Pick<InboxMessage, 'from' | 'messageId' | 'messageKind' | 'source'>;
|
type AutomationMessageLike = Pick<InboxMessage, 'from' | 'messageId' | 'messageKind' | 'source'>;
|
||||||
|
|
||||||
|
function getMessageId(message: AutomationMessageLike): string {
|
||||||
|
return typeof message.messageId === 'string' ? message.messageId.trim() : '';
|
||||||
|
}
|
||||||
|
|
||||||
export function isTaskStallRemediationMessage(message: AutomationMessageLike): boolean {
|
export function isTaskStallRemediationMessage(message: AutomationMessageLike): boolean {
|
||||||
if (message.messageKind === 'task_stall_remediation') {
|
if (message.messageKind === 'task_stall_remediation') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageId = typeof message.messageId === 'string' ? message.messageId.trim() : '';
|
|
||||||
return (
|
return (
|
||||||
message.source === 'system_notification' &&
|
message.source === 'system_notification' &&
|
||||||
message.from === 'system' &&
|
message.from === 'system' &&
|
||||||
messageId.startsWith('task-stall:')
|
getMessageId(message).startsWith('task-stall:')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isReviewPickupEscalationMessage(message: AutomationMessageLike): boolean {
|
||||||
|
return (
|
||||||
|
message.source === 'system_notification' &&
|
||||||
|
message.from === 'system' &&
|
||||||
|
getMessageId(message).startsWith('member-work-sync-review-pickup-escalation:')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -585,6 +585,31 @@ Messages:
|
||||||
expect(result.map((message) => message.messageId)).toEqual(['msg-2']);
|
expect(result.map((message) => message.messageId)).toEqual(['msg-2']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('hides review pickup escalation automation rows from conversational message counts by default', () => {
|
||||||
|
const messages = [
|
||||||
|
makeMessage({
|
||||||
|
messageId: 'member-work-sync-review-pickup-escalation:abc123',
|
||||||
|
from: 'system',
|
||||||
|
to: 'lead',
|
||||||
|
source: 'system_notification',
|
||||||
|
summary: 'Review pickup still pending',
|
||||||
|
text: 'Review pickup needs lead attention.\n\nReviewer: tom',
|
||||||
|
}),
|
||||||
|
makeMessage({
|
||||||
|
messageId: 'msg-2',
|
||||||
|
text: 'Visible message',
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = filterTeamMessages(messages, {
|
||||||
|
timeWindow: null,
|
||||||
|
filter: { from: new Set(), to: new Set(), showNoise: true },
|
||||||
|
searchQuery: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.map((message) => message.messageId)).toEqual(['msg-2']);
|
||||||
|
});
|
||||||
|
|
||||||
it('can include task stall remediation automation rows for the activity timeline', () => {
|
it('can include task stall remediation automation rows for the activity timeline', () => {
|
||||||
const messages = [
|
const messages = [
|
||||||
makeMessage({
|
makeMessage({
|
||||||
|
|
@ -608,4 +633,27 @@ Messages:
|
||||||
'task-stall:demo:task-a:legacy-epoch',
|
'task-stall:demo:task-a:legacy-epoch',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps review pickup escalation hidden even when regular automation rows are included', () => {
|
||||||
|
const messages = [
|
||||||
|
makeMessage({
|
||||||
|
messageId: 'member-work-sync-review-pickup-escalation:abc123',
|
||||||
|
from: 'system',
|
||||||
|
to: 'lead',
|
||||||
|
source: 'system_notification',
|
||||||
|
summary: 'Review pickup still pending',
|
||||||
|
text: 'Review pickup needs lead attention.\n\nReviewer: tom',
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = filterTeamMessages(messages, {
|
||||||
|
includeAutomationEvents: true,
|
||||||
|
timeWindow: null,
|
||||||
|
filter: { from: new Set(), to: new Set(), showNoise: true },
|
||||||
|
searchQuery: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue