mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-10 12:37:55 +01:00
Clarify recovery false-positive controls
This commit is contained in:
1 parent
8e16b8744b
commit
f19f9766df
6 files changed
+21
-21
No files matched your search
@@ -244,7 +244,7 @@ export const resolveIssueRecoveryActionSchema = z.object({
|
||||
) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: "This recovery outcome may only move the source issue to done or in_review",
|
||||
message: "This recovery outcome requires sourceIssueStatus to be done or in_review",
|
||||
path: ["sourceIssueStatus"],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ interface IssueChatThreadProps {
|
||||
successfulRunHandoff?: SuccessfulRunHandoffState | null;
|
||||
recoveryAction?: IssueRecoveryAction | null;
|
||||
onResolveRecoveryAction?: (outcome: RecoveryResolveOutcome) => void;
|
||||
canCancelRecoveryAction?: boolean;
|
||||
canFalsePositiveRecoveryAction?: boolean;
|
||||
legacyRecoverySourceIssue?: {
|
||||
identifier: string | null;
|
||||
href: string;
|
||||
@@ -3621,7 +3621,7 @@ export function IssueChatThread({
|
||||
successfulRunHandoff = null,
|
||||
recoveryAction = null,
|
||||
onResolveRecoveryAction,
|
||||
canCancelRecoveryAction = false,
|
||||
canFalsePositiveRecoveryAction = false,
|
||||
legacyRecoverySourceIssue = null,
|
||||
companyId,
|
||||
projectId,
|
||||
@@ -4263,7 +4263,7 @@ export function IssueChatThread({
|
||||
action={recoveryAction}
|
||||
agentMap={agentMap}
|
||||
onResolve={onResolveRecoveryAction}
|
||||
canCancelRecovery={canCancelRecoveryAction}
|
||||
canFalsePositive={canFalsePositiveRecoveryAction}
|
||||
/>
|
||||
) : null}
|
||||
{legacyRecoverySourceIssue ? (
|
||||
|
||||
@@ -182,7 +182,7 @@ describe("IssueRecoveryActionCard", () => {
|
||||
|
||||
it("does not offer blocked recovery resolution without a blocker selection flow", () => {
|
||||
const node = render(
|
||||
<IssueRecoveryActionCard action={buildAction()} onResolve={() => {}} canCancelRecovery />,
|
||||
<IssueRecoveryActionCard action={buildAction()} onResolve={() => {}} canFalsePositive />,
|
||||
);
|
||||
click(node.querySelector("[data-testid='recovery-action-resolve-trigger']"));
|
||||
|
||||
@@ -193,7 +193,7 @@ describe("IssueRecoveryActionCard", () => {
|
||||
expect(document.body.textContent).not.toContain("Mark blocked");
|
||||
});
|
||||
|
||||
it("hides false-positive options unless canCancelRecovery is set", () => {
|
||||
it("hides false-positive options unless canFalsePositive is set", () => {
|
||||
const first = render(
|
||||
<IssueRecoveryActionCard action={buildAction()} onResolve={() => {}} />,
|
||||
);
|
||||
@@ -207,7 +207,7 @@ describe("IssueRecoveryActionCard", () => {
|
||||
|
||||
const onResolve = vi.fn();
|
||||
const second = render(
|
||||
<IssueRecoveryActionCard action={buildAction()} onResolve={onResolve} canCancelRecovery />,
|
||||
<IssueRecoveryActionCard action={buildAction()} onResolve={onResolve} canFalsePositive />,
|
||||
);
|
||||
click(second.querySelector("[data-testid='recovery-action-resolve-trigger']"));
|
||||
expect(document.body.textContent).toContain("False positive, done");
|
||||
|
||||
@@ -37,8 +37,8 @@ export interface IssueRecoveryActionCardProps {
|
||||
forcedState?: RecoveryCardCardState;
|
||||
/** Optional click handler for resolve menu actions. If omitted, the buttons are not rendered. */
|
||||
onResolve?: (outcome: RecoveryResolveOutcome) => void;
|
||||
/** Whether the viewer can run destructive board-only actions (e.g. cancel recovery). */
|
||||
canCancelRecovery?: boolean;
|
||||
/** Whether the viewer can run destructive board-only actions (e.g. false-positive dismissal). */
|
||||
canFalsePositive?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ export function IssueRecoveryActionCard({
|
||||
agentMap,
|
||||
forcedState,
|
||||
onResolve,
|
||||
canCancelRecovery = false,
|
||||
canFalsePositive = false,
|
||||
className,
|
||||
}: IssueRecoveryActionCardProps) {
|
||||
const cardState: RecoveryCardCardState = forcedState ?? deriveRecoveryCardState(action);
|
||||
@@ -364,7 +364,7 @@ export function IssueRecoveryActionCard({
|
||||
|
||||
const showResolveActions = onResolve !== undefined && cardState !== "resolved";
|
||||
const visibleResolveOptions = RESOLVE_OPTIONS.filter((option) => {
|
||||
if (option.boardOnly && !canCancelRecovery) return false;
|
||||
if (option.boardOnly && !canFalsePositive) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
@@ -615,7 +615,7 @@ type IssueDetailChatTabProps = {
|
||||
successfulRunHandoff: Issue["successfulRunHandoff"] | null;
|
||||
recoveryAction: Issue["activeRecoveryAction"];
|
||||
onResolveRecoveryAction?: (outcome: import("../components/IssueRecoveryActionCard").RecoveryResolveOutcome) => void;
|
||||
canCancelRecoveryAction?: boolean;
|
||||
canFalsePositiveRecoveryAction?: boolean;
|
||||
legacyRecoverySourceIssue?: {
|
||||
identifier: string | null;
|
||||
href: string;
|
||||
@@ -686,7 +686,7 @@ const IssueDetailChatTab = memo(function IssueDetailChatTab({
|
||||
successfulRunHandoff,
|
||||
recoveryAction,
|
||||
onResolveRecoveryAction,
|
||||
canCancelRecoveryAction,
|
||||
canFalsePositiveRecoveryAction,
|
||||
legacyRecoverySourceIssue,
|
||||
comments,
|
||||
locallyQueuedCommentRunIds,
|
||||
@@ -896,7 +896,7 @@ const IssueDetailChatTab = memo(function IssueDetailChatTab({
|
||||
successfulRunHandoff={successfulRunHandoff}
|
||||
recoveryAction={recoveryAction ?? null}
|
||||
onResolveRecoveryAction={onResolveRecoveryAction}
|
||||
canCancelRecoveryAction={canCancelRecoveryAction}
|
||||
canFalsePositiveRecoveryAction={canFalsePositiveRecoveryAction}
|
||||
legacyRecoverySourceIssue={legacyRecoverySourceIssue ?? null}
|
||||
companyId={companyId}
|
||||
projectId={projectId}
|
||||
@@ -3887,7 +3887,7 @@ export function IssueDetail() {
|
||||
successfulRunHandoff={issue.successfulRunHandoff ?? null}
|
||||
recoveryAction={issue.activeRecoveryAction ?? null}
|
||||
onResolveRecoveryAction={handleResolveRecoveryAction}
|
||||
canCancelRecoveryAction={canResolveBoardRecoveryAction}
|
||||
canFalsePositiveRecoveryAction={canResolveBoardRecoveryAction}
|
||||
legacyRecoverySourceIssue={legacyRecoverySourceIssue}
|
||||
comments={threadComments}
|
||||
locallyQueuedCommentRunIds={locallyQueuedCommentRunIds}
|
||||
|
||||
@@ -65,11 +65,11 @@ function buildAction(overrides: Partial<IssueRecoveryAction> = {}): IssueRecover
|
||||
};
|
||||
}
|
||||
|
||||
function CardPanel({ caption, action, forcedState, canCancelRecovery }: {
|
||||
function CardPanel({ caption, action, forcedState, canFalsePositive }: {
|
||||
caption: string;
|
||||
action: IssueRecoveryAction;
|
||||
forcedState?: React.ComponentProps<typeof IssueRecoveryActionCard>["forcedState"];
|
||||
canCancelRecovery?: boolean;
|
||||
canFalsePositive?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<section className="space-y-2">
|
||||
@@ -81,7 +81,7 @@ function CardPanel({ caption, action, forcedState, canCancelRecovery }: {
|
||||
agentMap={storybookAgentMap}
|
||||
forcedState={forcedState}
|
||||
onResolve={() => {}}
|
||||
canCancelRecovery={canCancelRecovery}
|
||||
canFalsePositive={canFalsePositive}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
@@ -90,12 +90,12 @@ function CardPanel({ caption, action, forcedState, canCancelRecovery }: {
|
||||
function AllStatesPanel() {
|
||||
return (
|
||||
<div className="grid gap-5 lg:grid-cols-1">
|
||||
<CardPanel caption="State 1 · Recovery needed (default)" action={buildAction()} canCancelRecovery />
|
||||
<CardPanel caption="State 1 · Recovery needed (default)" action={buildAction()} canFalsePositive />
|
||||
<CardPanel
|
||||
caption="State 2 · Recovery in progress"
|
||||
action={buildAction({ outcome: "delegated", attemptCount: 2 })}
|
||||
forcedState="in_progress"
|
||||
canCancelRecovery
|
||||
canFalsePositive
|
||||
/>
|
||||
<CardPanel
|
||||
caption="State 3 · Observing active run (watchdog)"
|
||||
@@ -118,7 +118,7 @@ function AllStatesPanel() {
|
||||
},
|
||||
nextAction: "Board operator: assign an invokable owner or record a manual resolution.",
|
||||
})}
|
||||
canCancelRecovery
|
||||
canFalsePositive
|
||||
/>
|
||||
<CardPanel
|
||||
caption="State 5 · Recovery resolved"
|
||||
|
||||
Reference in new issue
Block a user