{"record":{"id":"7fe33858429013e2","repo":"JuliusBrussee/caveman","slug":"cacheengine-volatile-content-cannot-start-stable","errorCode":null,"errorMessage":"cacheengine: volatile content cannot start stable epoch","messagePattern":"cacheengine: volatile content cannot start stable epoch","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cacheengine/engine.go","lineNumber":242,"sourceCode":"func (e *Engine) StartEpoch(request PlanRequest) (Plan, error) {\n\tif e == nil || e.guard == nil {\n\t\treturn Plan{}, errors.New(\"cacheengine: nil engine\")\n\t}\n\tif e.configErr != nil {\n\t\treturn Plan{}, e.configErr\n\t}\n\tif err := validatePlanRequest(request); err != nil {\n\t\treturn Plan{}, err\n\t}\n\tprefix, stableSegments, err := stablePrefix(request.Segments, e.maxStablePrefixBytes)\n\tif err != nil {\n\t\treturn Plan{}, err\n\t}\n\tif len(stableSegments) == 0 {\n\t\treturn Plan{}, errors.New(\"cacheengine: no stable prefix\")\n\t}\n\tif len(cacheguard.DetectVolatile(prefix)) > 0 {\n\t\treturn Plan{}, errors.New(\"cacheengine: volatile content cannot start stable epoch\")\n\t}\n\tprofile := normalizedProfile(request.Profile)\n\teconomicsBasis := \"modeled_input_rate_units\"\n\tvar warnings []string\n\tif !profile.EconomicsKnown {\n\t\teconomicsBasis = \"unavailable\"\n\t\twarnings = []string{\"cache_economics_unavailable\"}\n\t}\n\tresult, err := e.guard.StartNewEpoch(epochKey(request.Scope, request.Epoch, profile.ID), prefix)\n\tif err != nil {\n\t\treturn Plan{}, err\n\t}\n\treturn Plan{\n\t\tDecision:       DecisionNewEpoch,\n\t\tReason:         string(cacheguard.DecisionNewEpoch),\n\t\tProfileID:      profile.ID,\n\t\tMode:           profile.Mode,\n\t\tAttribution:    profile.Attribution,","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/cacheengine/engine.go#L224-L260","documentation":"Returned by (*Engine).StartEpoch when cacheguard.DetectVolatile reports volatile content within the stable prefix bytes. Even though a non-empty stable prefix was found, its bytes contain patterns the cache guard classifies as volatile (timestamps, random IDs, and similar ever-changing content), and anchoring a cache epoch on such content would poison cache hit rates.","triggerScenarios":"A stable-flagged segment whose text embeds a timestamp, request ID, nonce, or other detectable volatile token at the epoch start. Content copied from logs or generated with Date.now()-style interpolation and marked Stable: true.","commonSituations":"System prompts templated with the current date; stable segments that include per-session IDs; refactors that moved dynamic fields above the static prefix; LLM scaffolds that interpolate 'today' into instructions.","solutions":["Move volatile content (dates, IDs, nonces) out of the leading stable prefix into later unstable segments","Fix segment metadata: content with detectable volatility must not be flagged stable","Hoist truly static instructions (persona, tool docs) to the very start of the prompt and keep them free of interpolated values","Re-run and inspect which offsets DetectVolatile flags to locate the offending bytes"],"exampleFix":"// before\nsegments := []cacheengine.Segment{\n    {Text: \"Assistant v2. Context date: \" + time.Now().Format(time.RFC3339), Stable: true},\n}\n\n// after\nsegments := []cacheengine.Segment{\n    {Text: \"Assistant v2.\", Stable: true},\n    {Text: \"Context date: \" + time.Now().Format(time.RFC3339), Stable: false},\n}","handlingStrategy":"validation","validationCode":"prefix := stablePrefixBytes(req.Segments)\nif volatiles := cacheguard.DetectVolatile(prefix); len(volatiles) > 0 {\n\treturn fmt.Errorf(\"stable prefix contains volatile content at %v; restructure prompt\", volatiles)\n}","typeGuard":"func prefixIsStable(prefix []byte) bool {\n\treturn len(prefix) > 0 && len(cacheguard.DetectVolatile(prefix)) == 0\n}","tryCatchPattern":"if _, err := eng.StartEpoch(req); err != nil {\n\tif err.Error() == \"cacheengine: volatile content cannot start stable epoch\" {\n\t\treturn Plan{}, fmt.Errorf(\"rebuild prompt: move timestamps/IDs below the stable prefix\")\n\t}\n\treturn Plan{}, err\n}","preventionTips":["Never interpolate dates, random IDs, or per-request values into stable-flagged segments","Add a lint step in the prompt builder that runs DetectVolatile over the stable prefix before StartEpoch"],"tags":["go","prompt-cache","validation","content-hygiene"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}