Skip to content

Commit 45d4b13

Browse files
authored
Set default Decision field for new retryables (#56)
* Set default Decision field for new retryables * a little tweak * Tweaks * More edits * more updates
1 parent 59ba0e1 commit 45d4b13

File tree

5 files changed

+71
-67
lines changed

5 files changed

+71
-67
lines changed

packages/retryable-monitor/core/retryableChecker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export const checkRetryables = async (
9797
ParentTx: `${PARENT_CHAIN_TX_PREFIX}${parentTxHash}`,
9898
createdAt: Date.now(), // fallback; won't overwrite real one
9999
timeout: Date.now() + SEVEN_DAYS_IN_SECONDS * 1000,
100-
status: 'Resolved',
100+
status: 'Executed',
101101
priority: 'Unset',
102102
metadata: {
103103
tokensDeposited: undefined,

packages/retryable-monitor/core/types.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,18 @@ export interface OnRetryableFoundParams {
6464
ParentTx: string
6565
createdAt: number
6666
timeout?: number
67-
status?:
68-
| 'Untriaged'
69-
| 'Investigating'
70-
| 'Resolved'
71-
| 'False Positive'
72-
| 'Expired'
67+
status:string
7368
priority?: 'High' | 'Medium' | 'Low' | 'Unset'
69+
decision?: string
7470
metadata?: {
7571
tokensDeposited?: string
7672
gasPriceProvided: string
7773
gasPriceAtCreation?: string
7874
gasPriceNow: string
7975
l2CallValue: string
8076
createdAt?: number
77+
decision?: string
78+
8179
}
8280
}
8381

packages/retryable-monitor/handlers/handleFailedRetryablesFound.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,15 @@ export const handleFailedRetryablesFound = async (
8181
ParentTx: `${PARENT_CHAIN_TX_PREFIX}${parentChainRetryableReport.transactionHash}`,
8282
createdAt: Number(childChainRetryableReport.createdAtTimestamp) * 1000,
8383
timeout: Number(childChainRetryableReport.timeoutTimestamp) * 1000,
84-
status: 'Untriaged',
84+
status: childChainRetryableReport.status,
8585
priority: 'Unset',
8686
metadata: {
8787
tokensDeposited: formattedTokenString,
8888
gasPriceProvided,
8989
gasPriceAtCreation,
9090
gasPriceNow,
9191
l2CallValue: l2CallValueFormatted,
92+
decision: 'Triage'
9293
},
9394
})
9495
}
Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import { notionClient, databaseId } from './createNotionClient'
22
import { postSlackMessage } from '../slack/postSlackMessage'
33

4-
/**
5-
* Queries the Notion database for untriaged retryable tickets and sends Slack alerts for each one.
6-
* This helps ensure that failed retryables don't go unnoticed and get proper investigation.
7-
*/
8-
94
export const alertUntriagedNotionRetryables = async () => {
105
const response = await notionClient.databases.query({
116
database_id: databaseId,
127
page_size: 100,
138
filter: {
14-
property: 'Status',
15-
select: { equals: 'Untriaged' },
9+
and: [
10+
{
11+
or: [
12+
{ property: 'Decision', select: { equals: 'Triage' } },
13+
{ property: 'Decision', select: { equals: 'Should Redeem' } },
14+
],
15+
},
16+
{
17+
property: 'Status',
18+
select: { does_not_equal: 'Executed' },
19+
},
20+
],
1621
},
1722
})
1823

@@ -21,9 +26,10 @@ export const alertUntriagedNotionRetryables = async () => {
2126
const timeoutStr = props?.timeoutTimestamp?.date?.start
2227
const retryableUrl =
2328
props?.ChildTx?.title?.[0]?.text?.content || '(unknown)'
29+
const decision = props?.Decision?.select?.name || '(unknown)'
2430

2531
await postSlackMessage({
26-
message: `⚠️ Retryable ticket still untriaged:\n• Retryable: ${retryableUrl}\n• Status: Untriaged\n• Timeout: ${timeoutStr}`,
32+
message: `⚠️ Retryable ticket still pending:\n• Retryable: ${retryableUrl}\n• Decision: ${decision}\n• Timeout: ${timeoutStr}`,
2733
})
2834
}
2935
}

packages/retryable-monitor/handlers/notion/syncRetryableToNotion.ts

Lines changed: 50 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export async function syncRetryableToNotion(
1212
ChildTx,
1313
ParentTx,
1414
createdAt,
15-
status = 'Untriaged',
15+
status,
1616
priority = 'Unset',
1717
metadata,
1818
} = input
@@ -31,32 +31,21 @@ export async function syncRetryableToNotion(
3131
const isRetryableFoundInNotion = search.results.length > 0
3232

3333
const rawCreatedAt = metadata?.createdAt ?? createdAt
34+
const createdAtMs =
35+
rawCreatedAt > 1e14
36+
? Math.floor(rawCreatedAt / 1000)
37+
: rawCreatedAt > 1e12
38+
? rawCreatedAt
39+
: rawCreatedAt > 1e10
40+
? rawCreatedAt
41+
: rawCreatedAt * 1000
3442

35-
// Normalize to milliseconds (ms) — only if needed
36-
let createdAtMs: number
37-
38-
if (rawCreatedAt > 1e14) {
39-
// Too big: microseconds → convert to ms
40-
createdAtMs = Math.floor(rawCreatedAt / 1000)
41-
} else if (rawCreatedAt > 1e12) {
42-
// Still too big: milliseconds → use as-is
43-
createdAtMs = rawCreatedAt
44-
} else if (rawCreatedAt > 1e10) {
45-
46-
createdAtMs = rawCreatedAt
47-
} else {
48-
// Normal seconds → convert to ms
49-
createdAtMs = rawCreatedAt * 1000
50-
}
5143
const notionProps: Record<string, any> = {
5244
ParentTx: { rich_text: [{ text: { content: ParentTx } }] },
53-
CreatedAt: {
54-
date: {
55-
start: new Date(createdAtMs).toISOString(),
56-
},
57-
},
45+
CreatedAt: { date: { start: new Date(createdAtMs).toISOString() } },
5846
Priority: { select: { name: priority } },
5947
}
48+
6049
if (input.timeout) {
6150
notionProps['timeoutTimestamp'] = {
6251
date: { start: new Date(input.timeout).toISOString() },
@@ -68,9 +57,7 @@ export async function syncRetryableToNotion(
6857
rich_text: [{ text: { content: metadata.gasPriceProvided } }],
6958
}
7059
notionProps['GasPriceAtCreation'] = {
71-
rich_text: [
72-
{ text: { content: metadata.gasPriceAtCreation ?? 'N/A' } },
73-
],
60+
rich_text: [{ text: { content: metadata.gasPriceAtCreation ?? 'N/A' } }],
7461
}
7562
notionProps['GasPriceNow'] = {
7663
rich_text: [{ text: { content: metadata.gasPriceNow } }],
@@ -97,38 +84,50 @@ export async function syncRetryableToNotion(
9784

9885
const props = (page as PageObjectResponse).properties
9986
const statusProp = props?.Status
100-
101-
let currentStatus: string | undefined = undefined
102-
if (statusProp && statusProp.type === 'select' && statusProp.select) {
103-
currentStatus = statusProp.select.name
104-
}
105-
106-
if (status === 'Resolved') {
107-
const resolvedProps: Record<string, any> = {
108-
Status: { select: { name: 'Resolved' } },
87+
const decisionProp = props?.Decision
88+
89+
const currentStatus =
90+
statusProp?.type === 'select' && statusProp.select
91+
? statusProp.select.name
92+
: undefined
93+
const currentDecision =
94+
decisionProp?.type === 'select' && decisionProp.select
95+
? decisionProp.select.name
96+
: undefined
97+
98+
// ✅ Handle Executed updates
99+
if (status === 'Executed') {
100+
const executedProps: Record<string, any> = {
101+
Status: { select: { name: 'Executed' } },
109102
}
110103

111104
if (input.timeout) {
112-
resolvedProps['timeoutTimestamp'] = {
105+
executedProps['timeoutTimestamp'] = {
113106
date: { start: new Date(input.timeout).toISOString() },
114107
}
115108
}
116109

117-
return await notionClient.pages
118-
.update({
119-
page_id: page.id,
120-
properties: resolvedProps,
121-
})
122-
.then(() => ({
123-
id: page.id,
124-
status: 'Resolved',
125-
isNew: false,
126-
}))
110+
if (!currentDecision && metadata?.decision) {
111+
executedProps['Decision'] = {
112+
select: { name: metadata.decision },
113+
}
114+
}
115+
116+
await notionClient.pages.update({
117+
page_id: page.id,
118+
properties: executedProps,
119+
})
120+
121+
return { id: page.id, status: 'Executed', isNew: false }
127122
}
128123

129-
// Only overwrite status if still Untriaged or missing
130-
if (currentStatus === 'Untriaged' || !currentStatus) {
131-
notionProps['Status'] = { select: { name: status } }
124+
notionProps['Status'] = { select: { name: status } }
125+
126+
// Only set Decision if it's missing
127+
if (!currentDecision && metadata?.decision) {
128+
notionProps['Decision'] = {
129+
select: { name: metadata.decision },
130+
}
132131
}
133132

134133
await notionClient.pages.update({
@@ -139,17 +138,17 @@ export async function syncRetryableToNotion(
139138
return { id: page.id, status: currentStatus ?? status, isNew: false }
140139
}
141140

142-
if (!isRetryableFoundInNotion && status === 'Resolved') {
143-
// Resolved but not found—skip
141+
// If not found and Executed, skip creation
142+
if (!isRetryableFoundInNotion && status === 'Executed') {
144143
return undefined
145144
}
146145

147-
// Retryable is new and unresolved—create full entry
148146
const created = await notionClient.pages.create({
149147
parent: { database_id: databaseId },
150148
properties: {
151149
ChildTx: { title: [{ text: { content: ChildTx } }] },
152150
Status: { select: { name: status } },
151+
...(metadata?.decision ? { Decision: { select: { name: metadata.decision } } } : {}),
153152
...notionProps,
154153
},
155154
})

0 commit comments

Comments
 (0)