{"record":{"id":"8301edad241dfd05","repo":"JuliusBrussee/caveman","slug":"caveman-agent-context-ttlturns-must-be-a-positive","errorCode":null,"errorMessage":"caveman agent: context ttlTurns must be a positive integer","messagePattern":"caveman agent: context ttlTurns must be a positive integer","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/primitives.ts","lineNumber":350,"sourceCode":"  readonly ttlTurns?: number;\n}\n\nexport function context(options: {\n  id: string;\n  kind: ContextKind;\n  source: string | FileSource;\n  stability: ContextStability;\n  safety?: SafetyClass;\n  priority?: ContextPriority;\n  recovery?: RecoveryKind;\n  cacheRegion?: CacheRegion;\n  privacy?: PrivacyClass;\n  opaque?: boolean;\n  ttlTurns?: number;\n}): ContextDefinition {\n  if (options.id.trim() === \"\") throw new Error(\"caveman agent: context id is required\");\n  if (options.ttlTurns !== undefined && (!Number.isSafeInteger(options.ttlTurns) || options.ttlTurns <= 0)) {\n    throw new Error(\"caveman agent: context ttlTurns must be a positive integer\");\n  }\n  const definition: ContextDefinition = {\n    kind: \"context\",\n    id: options.id,\n    segmentKind: options.kind,\n    source: options.source,\n    stability: options.stability,\n    safety: options.safety ?? \"S0\",\n    priority: options.priority ?? \"required\",\n    recovery: options.recovery ?? \"none\",\n    cacheRegion: options.cacheRegion ?? (options.stability === \"build\" ? \"frozen_prefix\" : \"live_zone\"),\n    privacy: options.privacy ?? \"local_sensitive\",\n    opaque: options.opaque ?? false,\n    ...(options.ttlTurns === undefined ? {} : { ttlTurns: options.ttlTurns }),\n  };\n  return Object.freeze(definition);\n}\n","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/primitives.ts#L332-L368","documentation":"Thrown by the context() builder when the optional ttlTurns is present but is not a safe integer greater than zero. ttlTurns bounds how many conversation turns a context segment stays alive, so 0, negatives, fractions, and non-numbers are invalid; omitting the field entirely means no turn-based expiry.","triggerScenarios":"Calling context({ ttlTurns: 0 }), ttlTurns: -3, ttlTurns: 2.5, ttlTurns: NaN, or ttlTurns beyond 2^53-1.","commonSituations":"Computing ttlTurns from a ratio (totalTurns / 4) and passing the fraction; using 0 to mean 'no limit' (the correct no-limit is to omit the option); config strings not coerced to numbers.","solutions":["Pass a positive integer (e.g. ttlTurns: 10) or omit ttlTurns when the segment should live for the whole run","Round computed values: ttlTurns: Math.max(1, Math.ceil(derived))","Coerce config values with Number() and validate Number.isSafeInteger before calling context()"],"exampleFix":"// before\ncontext({ id: 'scratch', kind: 'episodic', source: note, stability: 'volatile', ttlTurns: totalTurns / 4 });\n\n// after\ncontext({ id: 'scratch', kind: 'episodic', source: note, stability: 'volatile', ttlTurns: Math.max(1, Math.ceil(totalTurns / 4)) });","handlingStrategy":"validation","validationCode":"function toTtlTurns(raw: unknown): number | undefined {\n  if (raw === undefined) return undefined;\n  const n = typeof raw === 'number' ? raw : Number(raw);\n  if (!Number.isSafeInteger(n) || n <= 0) throw new Error(`ttlTurns must be a positive integer, got ${String(raw)}`);\n  return n;\n}","typeGuard":"function isTtlTurns(value: unknown): value is number { return typeof value === 'number' && Number.isSafeInteger(value) && value > 0; }","tryCatchPattern":null,"preventionTips":["Omit ttlTurns for whole-run segments instead of using 0","Round ratio-derived turn counts with Math.ceil","Keep ttlTurns as an integer field in config schemas"],"tags":["validation","context","numeric"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}