package config import ( "bytes" "encoding/json" "fmt" "sort" "strings" ) // effectivePipelineProjection is the single safe, schema-specific view used // for inspection, comparison, and identity. Runtime metadata and unresolved // family declarations have no slot in this type. type effectivePipelineProjection struct { Workspace WorkspaceConfig `yaml:"workspace" json:"workspace"` Campaigns CampaignsConfig `yaml:"campaigns" json:"campaigns"` Storage StorageConfig `yaml:"storage" json:"storage"` Spool SpoolConfig `yaml:"spool" json:"spool"` Cache CacheConfig `yaml:"cache" json:"cache"` Publish *PublishConfig `yaml:"publish" json:"publish"` WhisperX WhisperXConfig `yaml:"whisperx" json:"whisperx"` Seriatim SeriatimConfig `yaml:"seriatim" json:"seriatim"` Audita AuditaConfig `yaml:"audita" json:"audita"` Normalize *NormalizeConfig `yaml:"normalize" json:"normalize"` Trim *TrimConfig `yaml:"trim" json:"trim"` Render *RenderConfig `yaml:"render" json:"render"` Scriptorium *effectiveScriptoriumConfig `yaml:"scriptorium" json:"scriptorium"` Notarius *NotariusConfig `yaml:"notarius" json:"notarius"` Notification NotificationConfig `yaml:"notification" json:"notification"` } type effectiveScriptoriumConfig struct { Credentials []string `yaml:"credentials,omitempty" json:"credentials,omitempty"` Binary string `yaml:"binary" json:"binary"` ConfigPath string `yaml:"config_path" json:"config_path"` Timeout string `yaml:"timeout" json:"timeout"` RenderDebug bool `yaml:"render_debug" json:"render_debug"` Artifacts map[string]ScriptoriumArtifactConfig `yaml:"artifacts" json:"artifacts"` } type projectedPipelineValue struct { record EffectivePipelineValueRecord segments []string } func projectEffectivePipeline(cfg *PipelineConfig, logicalNotarius bool) effectivePipelineProjection { projection := effectivePipelineProjection{ Workspace: cfg.Workspace, Campaigns: cfg.Campaigns, Storage: cfg.Storage, Spool: cfg.Spool, Cache: cfg.Cache, Publish: cfg.Publish, WhisperX: cfg.WhisperX, Seriatim: cfg.Seriatim, Audita: cfg.Audita, Normalize: cfg.Normalize, Trim: cfg.Trim, Render: cfg.Render, Notarius: cfg.Notarius, Notification: cfg.Notification, } if cfg.Scriptorium != nil { projection.Scriptorium = &effectiveScriptoriumConfig{ Credentials: secretReferenceNames(cfg.Scriptorium.Credentials), Binary: cfg.Scriptorium.Binary, ConfigPath: cfg.Scriptorium.ConfigPath, Timeout: cfg.Scriptorium.Timeout, RenderDebug: cfg.Scriptorium.RenderDebug, Artifacts: cfg.Scriptorium.Artifacts, } } if logicalNotarius && cfg.Notarius != nil && cfg.resolution != nil && cfg.resolution.logicalNotariusCaptured { notarius := *cfg.Notarius notarius.ConfigPath = cfg.resolution.logicalNotariusConfig notarius.WorkingDirectory = cfg.resolution.logicalNotariusWorking projection.Notarius = ¬arius } return projection } func projectionJSON(projection effectivePipelineProjection) ([]byte, error) { data, err := json.Marshal(projection) if err != nil { return nil, fmt.Errorf("encode effective pipeline projection: %w", err) } return data, nil } func projectionValueTree(value any) (any, error) { data, err := json.Marshal(value) if err != nil { return nil, fmt.Errorf("encode typed pipeline projection: %w", err) } decoder := json.NewDecoder(bytes.NewReader(data)) decoder.UseNumber() var root any if err := decoder.Decode(&root); err != nil { return nil, fmt.Errorf("decode effective pipeline projection: %w", err) } return root, nil } func projectionValueRecords(projection effectivePipelineProjection) ([]EffectivePipelineValueRecord, error) { detailed, err := projectionDetailedRecords(projection) if err != nil { return nil, err } records := make([]EffectivePipelineValueRecord, 0, len(detailed)) for _, value := range detailed { records = append(records, value.record) } return records, nil } func projectionDetailedRecords(value any) ([]projectedPipelineValue, error) { decoded, err := projectionValueTree(value) if err != nil { return nil, err } root, ok := decoded.(map[string]any) if !ok { return nil, fmt.Errorf("effective pipeline projection must be a mapping") } var records []projectedPipelineValue appendProjectionRecords(&records, nil, root) sort.Slice(records, func(i, j int) bool { return records[i].record.Path < records[j].record.Path }) return records, nil } func appendProjectionRecords(records *[]projectedPipelineValue, segments []string, value any) { if mapping, ok := value.(map[string]any); ok && len(mapping) > 0 { keys := make([]string, 0, len(mapping)) for key := range mapping { keys = append(keys, key) } sort.Strings(keys) for _, key := range keys { child := append(append([]string(nil), segments...), key) appendProjectionRecords(records, child, mapping[key]) } return } encoded, _ := json.Marshal(value) path := strings.Join(segments, ".") *records = append(*records, projectedPipelineValue{ record: EffectivePipelineValueRecord{Path: path, Value: string(encoded)}, segments: append([]string(nil), segments...), }) }