package config import ( "slices" ck "go.maximumdirect.net/configkit" ) func cloneSelection(value *string) *string { if value == nil { return nil } copied := *value return &copied } func defaultNames(r *ck.Resolution, path ck.Path, target *[]string, inherited []string, reason string, source ck.Path) { if !r.IsExplicit(path) { ck.Default(r, path, target, slices.Clone(inherited), reason, source) } } // resolveSettings records root-derived defaults after all explicit assignments. func resolveSettings(c *Config, r *ck.Resolution) error { glossaries := ck.Keys("glossaries") protection := ck.Keys("protected_terms") defaultNames(r, protection, &c.ProtectedTerms, c.Glossaries, "protection defaults to selected glossaries", glossaries) rootValidation := ck.Keys("llm", "validation_profile") rootValidationInfo, _ := r.EntryInfo(rootValidation) inheritedValidation := r.IsExplicit(rootValidation) && !rootValidationInfo.Null && c.LLM.ValidationProfile != nil for i := range c.Pipeline.Stages { item := &c.Pipeline.Stages[i] base := ck.Keys("pipeline", "stages").Index(i) defaultNames(r, base.Key("glossaries"), &item.Glossaries, c.Glossaries, "inherit root glossaries", glossaries) defaultNames(r, base.Key("protected_terms"), &item.ProtectedTerms, c.ProtectedTerms, "inherit root protection", protection) threshold := ck.Keys("thresholds", item.Module) var value float64 switch item.Module { case "glossary": value = c.Thresholds.Glossary case "homophones": value = c.Thresholds.Homophones case "spoken_word": value = c.Thresholds.SpokenWord case "grammar": value = c.Thresholds.Grammar } ck.Default(r, base.Key("confidence_threshold"), &item.ConfidenceThreshold, value, "inherit module threshold", threshold) llm := base.Key("llm") rootLLM := ck.Keys("llm") proposal := llm.Key("proposal_profile") ck.Default(r, proposal, &item.LLM.ProposalProfile, cloneSelection(c.LLM.ProposalProfile), "inherit proposal profile", rootLLM.Key("proposal_profile")) ck.Default(r, llm.Key("transient_retries"), &item.LLM.TransientRetries, c.LLM.TransientRetries, "inherit retry budget", rootLLM.Key("transient_retries")) ck.Default(r, llm.Key("repair_attempts"), &item.LLM.RepairAttempts, c.LLM.RepairAttempts, "inherit repair budget", rootLLM.Key("repair_attempts")) ck.Default(r, llm.Key("operation_timeout"), &item.LLM.OperationTimeout, c.LLM.OperationTimeout, "inherit operation timeout", rootLLM.Key("operation_timeout")) ck.Default(r, base.Key("validation").Key("max_prompt_tokens"), &item.Validation.MaxPromptTokens, c.Validation.MaxPromptTokens, "inherit validation budget", ck.Keys("validation", "max_prompt_tokens")) ck.Default(r, base.Key("context").Key("description"), &item.Context.Description, c.Context.Description, "inherit description", ck.Keys("context", "description")) validation := llm.Key("validation_profile") info, _ := r.EntryInfo(validation) if r.IsExplicit(validation) && info.Null { item.LLM.ValidationProfile = cloneSelection(item.LLM.ProposalProfile) r.RecordDerivedDefault(validation, "validation defaults to proposal profile", proposal) } else if inheritedValidation { ck.Default(r, validation, &item.LLM.ValidationProfile, cloneSelection(c.LLM.ValidationProfile), "inherit validation profile", rootValidation) } else { ck.Default(r, validation, &item.LLM.ValidationProfile, cloneSelection(item.LLM.ProposalProfile), "validation defaults to proposal profile", proposal) } } if r.IsExplicit(rootValidation) && rootValidationInfo.Null { c.LLM.ValidationProfile = cloneSelection(c.LLM.ProposalProfile) r.RecordDerivedDefault(rootValidation, "validation defaults to proposal profile", ck.Keys("llm", "proposal_profile")) } else { ck.Default(r, rootValidation, &c.LLM.ValidationProfile, cloneSelection(c.LLM.ProposalProfile), "validation defaults to proposal profile", ck.Keys("llm", "proposal_profile")) } return nil }