{"record":{"id":"4c6c72624ae4aacf","repo":"JuliusBrussee/caveman","slug":"session-value-artifact-must-require-turn-index","errorCode":null,"errorMessage":"session-value artifact must require turn_index","messagePattern":"session-value artifact must require turn_index","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/routing/session_value.go","lineNumber":199,"sourceCode":"\t\treturn errors.New(\"session-value artifact outside validity window\")\n\t}\n\tif artifact.RollbackParentHash != \"\" && (!validSHA256Ref(artifact.RollbackParentHash) || artifact.RollbackParentHash == artifact.ArtifactHash) {\n\t\treturn errors.New(\"session-value artifact rollback lineage invalid\")\n\t}\n\tif !finite(artifact.QualityUncertaintyZ) || artifact.QualityUncertaintyZ <= 0 || artifact.QualityUncertaintyZ > 5 ||\n\t\t!finite(artifact.MaxInversePropensity) || artifact.MaxInversePropensity < 1 || artifact.MaxInversePropensity > 100 {\n\t\treturn errors.New(\"session-value artifact confidence policy invalid\")\n\t}\n\tfeatureNames := SessionValueFeatureNames()\n\tif len(artifact.FeatureSpecs) != len(featureNames) || len(artifact.Actions) == 0 {\n\t\treturn errors.New(\"session-value artifact has no features or actions\")\n\t}\n\tfor i, spec := range artifact.FeatureSpecs {\n\t\tif spec.Name != featureNames[i] || (i > 0 && artifact.FeatureSpecs[i-1].Name >= spec.Name) {\n\t\t\treturn errors.New(\"session-value artifact feature vocabulary or order invalid\")\n\t\t}\n\t\tif spec.Name == \"turn_index\" && !spec.Required {\n\t\t\treturn errors.New(\"session-value artifact must require turn_index\")\n\t\t}\n\t\tif !finite(spec.Mean) || !finite(spec.Scale) || spec.Scale <= 0 || !finite(spec.Min) || !finite(spec.Max) || spec.Min < 0 || spec.Max < spec.Min {\n\t\t\treturn fmt.Errorf(\"session-value feature %q bounds invalid\", spec.Name)\n\t\t}\n\t}\n\tseenActions := map[string]struct{}{}\n\tartifactPool := make([]Candidate, 0, len(artifact.Actions))\n\tfor i, action := range artifact.Actions {\n\t\twantID := CandidateActionID(Candidate{Provider: action.Provider, Model: action.Model, Effort: action.Effort})\n\t\tif wantID == \"\" || action.ActionID != wantID || (i > 0 && artifact.Actions[i-1].ActionID >= action.ActionID) {\n\t\t\treturn errors.New(\"session-value artifact action identity or order invalid\")\n\t\t}\n\t\tif _, duplicate := seenActions[action.ActionID]; duplicate {\n\t\t\treturn errors.New(\"session-value artifact duplicate action\")\n\t\t}\n\t\tseenActions[action.ActionID] = struct{}{}\n\t\tartifactPool = append(artifactPool, Candidate{Provider: action.Provider, Model: action.Model, Effort: action.Effort})\n\t\tif !finite(action.RewardEffectiveSampleSize) || action.RewardEffectiveSampleSize <= 0 ||","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/proxy/routing/session_value.go#L181-L217","documentation":"Among the feature specs, turn_index must be marked Required: true. The evaluator treats turn_index as always-present session metadata; an artifact that marks it optional would change missing-value semantics for every downstream model, so validation rejects it.","triggerScenarios":"A trainer that marks no feature as Required (the Go bool zero value false survives JSON round-trips); hand-editing the required flag off; a schema migration that drops the 'required' JSON key so it unmarshals as false.","commonSituations":"Generators that never set Required on any spec; feature-schema refactors that lose per-feature flags; copy-transform pipelines that rebuild structs field-by-field and skip booleans.","solutions":["Set Required: true on the turn_index spec during artifact generation.","Add a trainer-side check that exactly the intended features are Required, with turn_index among them.","Re-seal the artifact after fixing the flag so ArtifactHash covers the correction."],"exampleFix":"// before\n{\"name\": \"turn_index\", \"required\": false}\n\n// after\n{\"name\": \"turn_index\", \"required\": true}","handlingStrategy":"validation","validationCode":"// Before validation: turn_index must exist and be Required.\nfunc turnIndexRequired(specs []routing.SessionValueFeatureSpec) bool {\n\tfor _, spec := range specs {\n\t\tif spec.Name == \"turn_index\" {\n\t\t\treturn spec.Required\n\t\t}\n\t}\n\treturn false\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set the Required flag explicitly for every spec during generation; never rely on zero values.","Keep a trainer test asserting turn_index is present and required.","After fixing the flag, re-seal the artifact so its hash covers the change."],"tags":["routing","features","required-field","artifact"],"backgroundTag":"required-feature-missing","analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}