{"record":{"id":"a688c951060c6bb6","repo":"Yeachan-Heo/oh-my-codex","slug":"invalid-autopilot-context-timestamp-nowiso","errorCode":null,"errorMessage":"Invalid Autopilot context timestamp: ${nowIso}","messagePattern":"Invalid Autopilot context timestamp: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/hooks/keyword-detector.ts","lineNumber":253,"sourceCode":"  question_enforcement?: DeepInterviewQuestionEnforcementState;\n  [key: string]: unknown;\n}\n\nfunction slugifyAutopilotTask(text: string): string {\n  const slug = text\n    .replace(/(?:^|\\s)\\$?(?:oh-my-codex:)?autopilot\\b/gi, ' ')\n    .replace(/[^A-Za-z0-9]+/g, '-')\n    .replace(/^-+|-+$/g, '')\n    .toLowerCase()\n    .slice(0, 48)\n    .replace(/-+$/g, '');\n  return slug || 'autopilot-task';\n}\n\nfunction utcCompactTimestamp(nowIso: string): string {\n  const parsed = new Date(nowIso);\n  if (Number.isNaN(parsed.getTime())) {\n    throw new Error(`Invalid Autopilot context timestamp: ${nowIso}`);\n  }\n  return parsed.toISOString().replace(/[-:]/g, '').replace(/\\.\\d{3}Z$/, 'Z');\n}\n\nfunction isSafeAutopilotContextSnapshotPath(value: unknown): value is string {\n  const path = safeString(value).trim();\n  const contextPrefix = '.omx/context/';\n  const snapshotName = path.startsWith(contextPrefix) ? path.slice(contextPrefix.length) : '';\n  return path.startsWith('.omx/context/')\n    && path.endsWith('.md')\n    && !isAbsolute(path)\n    && !path.split('/').includes('..')\n    && !path.includes('\\\\')\n    && snapshotName !== ''\n    && !snapshotName.includes('/');\n}\n\nfunction isAutopilotRecoverySnapshotPath(path: string): boolean {","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/hooks/keyword-detector.ts#L235-L271","documentation":"Thrown by utcCompactTimestamp in the Autopilot keyword detector hook when the nowIso timestamp passed into the context snapshot flow cannot be parsed by new Date() (NaN time). The hook formats timestamps into a compact UTC form for snapshot filenames and refuses invalid date strings.","triggerScenarios":"Passing nowIso values like 'not-a-date', '' (empty string is invalid), '2026-13-45', or an already-compact form like '20260827T120000Z' that Date can't parse, into the Autopilot context snapshot path.","commonSituations":"Test fixtures with hand-written timestamp strings; pipeline code reformatting the ISO string before passing it (double-formatting); clock mocks returning undefined/null that stringifies to 'undefined'; locale-specific date strings.","solutions":["Pass a value produced by new Date().toISOString() directly without reformatting","Fix the upstream producer of nowIso to emit strict ISO-8601 (YYYY-MM-DDTHH:mm:ss.sssZ)","In tests, generate timestamps with new Date().toISOString() instead of hardcoding plausible-looking strings"],"exampleFix":"// before\ndetectKeyword(text, { nowIso: '20260827T120000Z' });\n\n// after\ndetectKeyword(text, { nowIso: new Date().toISOString() });","handlingStrategy":"validation","validationCode":"function isValidIso(value: string): boolean {\n  return !Number.isNaN(new Date(value).getTime());\n}\nconst safeIso = isValidIso(nowIso) ? nowIso : new Date().toISOString();","typeGuard":"function isIsoDateString(v: unknown): v is string {\n  return typeof v === 'string' && !Number.isNaN(new Date(v).getTime());\n}","tryCatchPattern":"try { detectKeyword(text, { nowIso }); } catch (err) {\n  if ((err as Error).message.startsWith('Invalid Autopilot context timestamp')) {\n    return detectKeyword(text, { nowIso: new Date().toISOString() });\n  }\n  throw err;\n}","preventionTips":["Always pass new Date().toISOString() output verbatim","Type the nowIso parameter as a branded ISO string in your own wrappers","In tests, generate timestamps dynamically instead of hardcoding strings"],"tags":["date-parsing","timestamp","validation"],"backgroundTag":"invalid-date-format","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}