← Public packages
@kentcdodds/kody-issue-triage
Loop-safe triage for Kody run errors and fleet package-runtime error-rate elevations. Wakes Cole (Grok Bot) to decide; Cursor agents only when Cole escalates.
src/shared.ts
530 lines · 16.7 KB · TypeScriptexport const SELF_KODY_ID = 'kody-issue-triage'
export const SELF_PACKAGE_ID = 'bec7387f-dc65-4e05-b136-8518e4a80ab7'
export const discordChannelId = '1530233790516039881'
export const agentModelId = 'grok-4.6'
export const agentRepository = 'https://github.com/kentcdodds/use-kody'
export const agentRepoSlug = 'kentcdodds/use-kody'
export const agentRef = 'main'
export const kodyRepository = 'https://github.com/kentcdodds/kody'
export const kodyRepoSlug = 'kentcdodds/kody'
export const kodyRef = 'main'
/** Max cloud agents spawned per clock hour. */
export const maxAgentsPerHour = 3
/** New unique fingerprints in an hour above this pauses spawning. */
export const fingerprintAnomalyThreshold = 15
/** Raw error events in an hour above this pauses spawning. */
export const eventAnomalyThreshold = 80
/** Stale in-flight lease / dead-agent window. */
export const leaseStaleMs = 2 * 60 * 60 * 1000
/** Re-triage a terminal fingerprint only after this cooldown. */
export const retriageCooldownMs = 24 * 60 * 60 * 1000
export const SKIP_SURFACES = new Set(['execute'])
/** Queued then closed without an agent because the sample run was agent execute. */
export const SKIPPED_EXECUTE_STATUS = 'skipped_execute'
/** Sibling triage packages whose ./record-outcome throws become standing fingerprints. */
export const SIBLING_TRIAGE_KODY_IDS = new Set([
'kody-issue-triage',
'platform-feedback-triage',
'sentry-triage',
])
export const IN_FLIGHT_STATUSES = new Set(['queued', 'claimed', 'spawned'])
export const HANDLED_OUTCOMES = new Set(['fixed', 'recommendation'])
/** Outcomes that mean "do not spawn another agent for this family". */
export const SKIP_SPAWN_OUTCOMES = new Set([
...HANDLED_OUTCOMES,
'resolved_noise',
'ignored',
])
export const TERMINAL_OUTCOMES = new Set([
'fixed',
'ignored',
'resolved_noise',
'recommendation',
'loop_detected',
'failed',
])
export type RunSnippet = {
id?: string
surface?: string | null
name?: string | null
package_id?: string | null
kody_id?: string | null
job_id?: string | null
error_name?: string | null
error_message?: string | null
started_at?: string | null
activity_url?: string | null
/** Present on `run_list` / `run_get`. `run.error.recorded` omits this blob. */
metadata?: Record<string, unknown> | null
}
export type FingerprintRecord = {
fingerprint: string
surface: string
owner: string
package_id: string | null
kody_id: string | null
error_family: string
sample_message: string
sample_run_id: string | null
activity_url: string | null
sample_run_ids: string[]
count: number
first_seen: string
last_seen: string
status: string
agent_id: string | null
agent_url: string | null
kody_agent_id: string | null
kody_agent_url: string | null
classification: string | null
discord_message_id: string | null
spawned_at: string | null
completed_at: string | null
outcome: string | null
summary: string | null
pr_url: string | null
merge_commit_url: string | null
deploy_url: string | null
card_stage: string | null
}
export type TriageOutcome =
| 'fixed'
| 'ignored'
| 'resolved_noise'
| 'recommendation'
| 'loop_detected'
| 'failed'
export function hourBucket(date = new Date()) {
return date.toISOString().slice(0, 13)
}
export function toLowerKebabCase(value: string) {
return String(value ?? '')
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
}
export function truncate(text: unknown, maxLength: number) {
const value = String(text ?? '')
return value.length <= maxLength ? value : `${value.slice(0, maxLength - 1)}…`
}
export function sanitizeForPrompt(text: unknown) {
return String(text ?? '')
.replaceAll('`', 'ˋ')
.replaceAll('«', '<')
.replaceAll('»', '>')
}
export const PACKAGE_CALLER_VALIDATION_FAMILY = 'package-caller-validation'
export function isPackageCallerValidation(text: string) {
const raw = String(text ?? '')
if (!raw) return false
if (
/available event types/i.test(raw) ||
/call list-event-types/i.test(raw) ||
/could not resolve that event type/i.test(raw) ||
/requires (?:id or )?eventtypeid/i.test(raw) ||
/requires eventtypeslug/i.test(raw) ||
/event type with id .+ not found/i.test(raw) ||
/create-webhook requires/i.test(raw)
) {
return true
}
const kebab = toLowerKebabCase(raw)
return (
kebab.includes('available-event-types') ||
kebab.includes('could-not-resolve-that-event-type') ||
kebab.includes('requires-eventtypeid') ||
kebab.includes('requires-id-or-eventtypeid') ||
kebab.includes('create-webhook-requires') ||
(kebab.includes('event-type-with-id') && kebab.includes('not-found'))
)
}
function knownFamilyFrom(text: string) {
const m = String(text ?? '')
if (isPackageCallerValidation(m)) return PACKAGE_CALLER_VALIDATION_FAMILY
if (/Execution timed out after \d+(?:s|ms)/i.test(m)) return 'execution-timed-out'
if (/The platform interrupted this run before completion/i.test(m)) {
return 'platform-interrupted'
}
if (m.includes('Cannot read properties of undefined')) {
return 'cannot-read-properties-of-undefined'
}
if (m.includes('Cannot read properties of null')) {
return 'cannot-read-properties-of-null'
}
if (m.includes('Dynamic worker concurrency limit exceeded')) {
return 'dynamic-worker-concurrency-limit-exceeded'
}
if (m.includes('Plan limit reached') && m.includes('repo sessions')) {
return 'repo-session-plan-limit'
}
if (m.includes('Durable Object reset because its code was updated')) {
return 'durable-object-code-reset'
}
if (m.includes('packageContext is not a function')) {
return 'package-context-not-function'
}
if (m.includes('HTTP Error: 500')) return 'http-500'
if (m.includes('stale running TTL')) return 'stale-ttl-interrupted'
if (m.includes('REPO_SESSION_INDEX')) return 'repo-session-index-unbound'
if (m.includes('Network connection lost')) return 'network-lost'
if (m.startsWith('internal error; reference')) return 'internal-error'
if (m.includes('Plain repo') && m.includes('not found')) {
return 'plain-repo-not-found'
}
if (m.includes('packageStorage() cannot access')) {
return 'package-storage-context'
}
if (m.includes('RPC stub used after being disposed')) return 'rpc-disposed'
return null
}
function innerErrorsFrom(message: string) {
const found: string[] = []
for (const match of message.matchAll(/"error"\s*:\s*"((?:\\.|[^"\\])*)"/g)) {
found.push(match[1].replaceAll('\\"', '"'))
}
return found
}
/** Stable family for `Something failed: {json with instance keys}` wrappers. */
export function wrapperFamilyOf(text: string) {
const raw = String(text || '')
const messageMatch = raw.match(/^(.{3,80}?)\s+failed:\s*\{/i)
if (messageMatch) return toLowerKebabCase(`${messageMatch[1]} failed`)
const kebab = toLowerKebabCase(raw)
const keyVariant = kebab.match(/^([a-z0-9]+(?:-[a-z0-9]+)*)-failed-key-/)
if (keyVariant) return `${keyVariant[1]}-failed`
if (kebab.startsWith('shade-workflow-event-failed')) {
return 'shade-workflow-event-failed'
}
return null
}
export function normalizeErrorFamily(message: string | null | undefined) {
const m = String(message ?? '')
const fromFull = knownFamilyFrom(m)
if (fromFull) return fromFull
for (const inner of innerErrorsFrom(m)) {
const known = knownFamilyFrom(inner)
if (known) return known
}
const wrapper = wrapperFamilyOf(m)
if (wrapper) return wrapper
const cleaned = m
.replace(
/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,
'<id>',
)
.replace(/reference = [a-z0-9]+/gi, 'reference = <id>')
.replace(/\{[\s\S]*$/, '')
.replace(/\d+/g, 'N')
.slice(0, 80)
return toLowerKebabCase(cleaned) || 'unknown'
}
/** Collapse stored family variants so peer matching sees one issue. */
export function coarseErrorFamily(familyOrMessage: string) {
const raw = String(familyOrMessage || '')
const family = raw.includes(' ') ? normalizeErrorFamily(raw) : toLowerKebabCase(raw)
if (isPackageCallerValidation(raw) || isPackageCallerValidation(family)) {
return PACKAGE_CALLER_VALIDATION_FAMILY
}
if (
family === 'timeout-90s' ||
family.startsWith('execution-timed-out') ||
family.startsWith('timeout-')
) {
return 'execution-timed-out'
}
if (family.startsWith('cannot-read-properties-of-undefined')) {
return 'cannot-read-properties-of-undefined'
}
if (family.startsWith('cannot-read-properties-of-null')) {
return 'cannot-read-properties-of-null'
}
if (family.startsWith('dynamic-worker-concurrency-limit-exceeded')) {
return 'dynamic-worker-concurrency-limit-exceeded'
}
if (family.startsWith('durable-object-code-reset')) {
return 'durable-object-code-reset'
}
if (
family === 'platform-interrupted' ||
family.startsWith('the-platform-interrupted-this-run')
) {
return 'platform-interrupted'
}
if (family === 'internal-error' || family.startsWith('internal-error-')) {
return 'internal-error'
}
return wrapperFamilyOf(raw) || wrapperFamilyOf(family) || family
}
export type FamilyMatchInput = {
error_family: string
sample_message?: string | null
}
/** All coarse families a stored row can match under, including wrappers. */
export function matchFamiliesFor(record: FamilyMatchInput) {
const families = new Set<string>()
const add = (value: string | null | undefined) => {
if (!value) return
families.add(coarseErrorFamily(value))
const wrapper = wrapperFamilyOf(value)
if (wrapper) families.add(wrapper)
if (value.includes(' ') || value.includes('{')) {
families.add(normalizeErrorFamily(value))
}
}
add(record.error_family)
add(record.sample_message || '')
return families
}
export function matchFamiliesOverlap(left: FamilyMatchInput, right: FamilyMatchInput) {
const rightFamilies = matchFamiliesFor(right)
for (const family of matchFamiliesFor(left)) {
if (rightFamilies.has(family)) return true
}
return false
}
export function nextFingerprintStatusAfterEvent(input: {
status: string
completedAt: string | null
kodyAgentId: string | null
runStartedAt?: string | null
now?: number
}) {
if (input.status === SKIPPED_EXECUTE_STATUS) return 'queued'
if (IN_FLIGHT_STATUSES.has(input.status)) return input.status
if (input.status === 'ignored' || input.status === 'resolved_noise') {
return input.status
}
if (input.kodyAgentId) return input.status
const now = input.now ?? Date.now()
const completedAt = input.completedAt ? Date.parse(input.completedAt) : 0
if (completedAt && now - completedAt < retriageCooldownMs) return input.status
const runStarted = input.runStartedAt ? Date.parse(input.runStartedAt) : now
if (
completedAt &&
!Number.isNaN(runStarted) &&
runStarted <= completedAt
) {
return input.status
}
return 'queued'
}
export function ownerFor(run: RunSnippet) {
return run.kody_id || run.package_id || run.name || 'ad-hoc'
}
export function fingerprintFor(run: RunSnippet) {
const surface = run.surface || 'unknown'
const owner = ownerFor(run)
const family = normalizeErrorFamily(run.error_message)
return `${surface}:${owner}:${family}`
}
export function utcDayKey(iso: string | null | undefined) {
const parsed = iso ? Date.parse(iso) : Number.NaN
if (!Number.isFinite(parsed)) return new Date().toISOString().slice(0, 10)
return new Date(parsed).toISOString().slice(0, 10)
}
export function fleetRateFingerprintFor(input: {
window: 'hour' | 'day'
day: string
}) {
return `rate:fleet:${input.window}:${input.day}`
}
export function isFleetRateFingerprint(fingerprint: string) {
return /^rate:fleet:(hour|day):\d{4}-\d{2}-\d{2}$/.test(fingerprint)
}
function exportNameOf(run: RunSnippet) {
const name = String(run.name || '')
if (name === './record-outcome' || name === 'record-outcome') {
return './record-outcome'
}
return name
}
export function metadataSource(run: Pick<RunSnippet, 'metadata'>): string | null {
const source = run.metadata?.source
return typeof source === 'string' && source ? source : null
}
export function metadataSourceType(
run: Pick<RunSnippet, 'metadata'>,
): string | null {
const sourceType = run.metadata?.sourceType
return typeof sourceType === 'string' && sourceType ? sourceType : null
}
/**
* Unsaved `workflows.create` from MCP execute (`dynwf-*`, name `inline-code`).
* Package-owned workflows stay visible even when they time out.
*/
export function isUnsavedInlineWorkflow(run: RunSnippet): boolean {
if ((run.surface || '') !== 'workflow') return false
if (run.package_id || run.kody_id) return false
if ((run.name || '') !== 'inline-code') return false
const sourceType = metadataSourceType(run)
return sourceType === 'inline' || sourceType == null
}
/** Agent MCP `execute`, a package run invoked from that execute, or its inline workflow. */
export function isAgentExecuteOrigin(run: RunSnippet): boolean {
if ((run.surface || '') === 'execute') return true
if (metadataSource(run) === 'execute') return true
return isUnsavedInlineWorkflow(run)
}
export function isExecutionTimedOut(
run: Pick<RunSnippet, 'error_message'>,
): boolean {
return coarseErrorFamily(normalizeErrorFamily(run.error_message)) ===
'execution-timed-out'
}
/** Soft-ignore Activity rows for MCP execute timeouts only. */
export function shouldIgnoreAgentExecuteTimeout(run: RunSnippet): boolean {
return isAgentExecuteOrigin(run) && isExecutionTimedOut(run)
}
export const PLATFORM_WEATHER_NOTE =
'Ignored: platform isolate-reset weather (skills retriever interrupt / 2500ms observer timeout / worker cap, or system-email /api/status interrupt). Standing noise; do not refill Activity.'
export function isPlatformInterrupted(
run: Pick<RunSnippet, 'error_name' | 'error_message'>,
): boolean {
if (String(run.error_name || '') === 'platform_interrupted') return true
return /The platform interrupted this run before completion/i.test(
String(run.error_message || ''),
)
}
/** Skills retriever isolate weather and system-email /api/status interrupts. */
export function shouldIgnorePlatformWeather(run: RunSnippet): boolean {
const surface = run.surface || ''
const kodyId = run.kody_id || ''
const name = run.name || ''
const message = String(run.error_message || '')
const skillsRetriever =
surface === 'retriever' && (kodyId === 'skills' || name === 'skills')
if (skillsRetriever) {
if (isPlatformInterrupted(run)) return true
if (message.includes('Dynamic worker concurrency limit exceeded')) return true
if (/Execution timed out after \d+ms/i.test(message)) return true
}
const systemEmailStatus =
surface === 'app_fetch' &&
kodyId === 'system-email' &&
(name === '/api/status' || name === 'api/status')
return Boolean(systemEmailStatus && isPlatformInterrupted(run))
}
/** Soft-ignore note for agent MCP execute-origin Activity rows. */
export const AGENT_EXECUTE_NOISE_NOTE =
'Ignored: agent MCP execute origin (execute surface, metadata.source=execute, or unsaved inline-code). The calling agent already saw the error; standing package/job/subscription failures stay open.'
/**
* Soft-ignore every agent MCP execute-origin Activity row. The caller already
* got the failure in the execute response, so Open errors should not keep it.
* Standing package / job / subscription failures are not this.
*/
export function shouldIgnoreAgentExecuteNoise(run: RunSnippet): boolean {
return isAgentExecuteOrigin(run)
}
export function isSelfPackageRun(run: RunSnippet): boolean {
return run.kody_id === SELF_KODY_ID || run.package_id === SELF_PACKAGE_ID
}
export function spawnSkipReasonForRecord(
record: Pick<
FingerprintRecord,
| 'fingerprint'
| 'surface'
| 'owner'
| 'package_id'
| 'kody_id'
| 'sample_run_id'
>,
sampleRun?: RunSnippet | null,
): string | null {
if (isFleetRateFingerprint(record.fingerprint)) return null
if ((record.surface || '') === 'execute') return 'agent-execute'
if (
(record.surface || '') === 'workflow' &&
record.owner === 'inline-code' &&
!record.package_id &&
!record.kody_id
) {
return 'agent-execute'
}
if (!sampleRun) return null
return isAgentExecuteOrigin(sampleRun) ? 'agent-execute' : null
}
export function skipReason(run: RunSnippet): string | null {
const surface = run.surface || ''
if (SKIP_SURFACES.has(surface)) {
return 'agent-execute'
}
if (isAgentExecuteOrigin(run)) return 'agent-execute'
if (isSelfPackageRun(run)) {
return 'self-package'
}
const family = normalizeErrorFamily(run.error_message)
const coarse = coarseErrorFamily(family)
if (
family.includes('smoke-test') ||
coarse.includes('smoke-test') ||
family.startsWith('unknown-fingerprint-smoke')
) {
return 'smoke-test'
}
const siblingTriage = Boolean(
run.kody_id && SIBLING_TRIAGE_KODY_IDS.has(run.kody_id),
)
if (siblingTriage && exportNameOf(run) === './record-outcome') {
return 'sibling-triage-export'
}
if (
siblingTriage &&
(family.startsWith('shipped-requires-') ||
family.startsWith('needs-decision-requires-') ||
family.startsWith('unknown-fingerprint'))
) {
return 'triage-validation'
}
return null
}
export function activityUrlFor(runId: string | null | undefined) {
if (!runId) return null
return `https://kody.codes/account/activity/${runId}`
}