package oracle import ( "fmt" "strings" ) // GenerateDirectives builds strategy directives from a reading's hexagram // state, source identifier, and engagement style. // // The primary directive comes from the inner+outer trigram decomposition. // Additional directives come from each changing line, identifying which // specific dimension is in flux. func GenerateDirectives(r *Reading, source string, style EngagementStyle) []Directive { var directives []Directive inner := r.InnerTrigram() outer := r.OuterTrigram() domain := TrigramToDomain(outer) intention := TrigramToIntention(inner) // Primary directive: intention + domain + source + style. primary := Directive{ Type: directiveTypeForSource(source), Query: buildQuery(intention, domain, source, style), Domain: domain, Intention: intention, Style: style, ChangingBit: -1, // primary, not from a changing line } directives = append(directives, primary) // Changing line directives: each changing line adds a dimension-specific // follow-up identifying what is in flux. for _, lineIdx := range r.ChangingLines() { bitWithinTrigram := lineIdx % 3 isInner := lineIdx < 3 d := Directive{ Type: directiveTypeForSource(source), Query: buildChangingLineQuery(bitWithinTrigram, isInner, source, style), Domain: domain, Intention: intention, Style: style, ChangingBit: lineIdx, } directives = append(directives, d) } return directives } // directiveTypeForSource maps a data source identifier to the appropriate // directive type. func directiveTypeForSource(source string) DirectiveType { switch source { case "self", "walk", "local": return DirectiveWalkWeight case "forage", "web", "search": return DirectiveSearch case "nostr", "relay": return DirectiveSubscribe default: return DirectiveFocus } } // buildQuery constructs a strategy string from intention, domain, source, and style. // For walk/self sources this produces a concise focus descriptor; for search // sources it produces a natural language query. func buildQuery(intention IntentionType, domain DomainType, source string, style EngagementStyle) string { keywords := DomainKeywords(domain) dtype := directiveTypeForSource(source) // Walk/self: concise focus tags, not a search sentence. if dtype == DirectiveWalkWeight { parts := []string{domainLabel(domain), intentionLabel(intention)} if len(keywords) > 1 { parts = append(parts, keywords[1]) // second keyword for variety } parts = append(parts, styleLabel(style)) return strings.Join(parts, "→") } // Search/subscribe: natural language query. prefix := IntentionPrefix(intention) var b strings.Builder b.WriteString(prefix) b.WriteString(" ") b.WriteString(source) if len(keywords) > 0 { b.WriteString(" ") b.WriteString(keywords[0]) } switch style { case StyleBroad: b.WriteString(" overview") case StyleTargeted: b.WriteString(" detail") case StyleReference: b.WriteString(" reference") case StyleSynthesis: b.WriteString(" synthesis") } return b.String() } func domainLabel(d DomainType) string { switch d { case DomainEmpirical: return "empirical" case DomainEmerging: return "emerging" case DomainCritiques: return "critiques" case DomainApplications: return "applied" case DomainVisualization: return "visual" case DomainFoundations: return "foundations" case DomainMethodology: return "method" case DomainCanon: return "canon" default: return "general" } } func intentionLabel(i IntentionType) string { switch i { case IntentEmpirical: return "evidence" case IntentEmerging: return "novelty" case IntentCritiques: return "failures" case IntentApplications: return "practice" case IntentVisualization: return "intuition" case IntentFoundations: return "axioms" case IntentMethodology: return "technique" case IntentCanon: return "standard" default: return "focus" } } func styleLabel(s EngagementStyle) string { switch s { case StyleBroad: return "broad" case StyleTargeted: return "targeted" case StyleReference: return "reference" case StyleSynthesis: return "synthesis" default: return "explore" } } // buildChangingLineQuery constructs a follow-up query for a changing line. func buildChangingLineQuery(bit int, isInner bool, source string, style EngagementStyle) string { dtype := directiveTypeForSource(source) // Walk/self: short dimension tag. if dtype == DirectiveWalkWeight { dim := changingBitLabel(bit, isInner) return dim + "→" + styleLabel(style) } // Search: natural language. focus := ChangingBitFocus(bit, isInner) return fmt.Sprintf("%s %s", focus, source) } func changingBitLabel(bit int, isInner bool) string { scope := "source" if isInner { scope = "understanding" } switch bit { case 0: return "bonding:" + scope case 1: return "constraint:" + scope case 2: return "energy:" + scope default: return "flux:" + scope } }