<EXTREMELY_IMPORTANT>
You have superpowers.

**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**

---
name: using-superpowers
description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions
---

<SUBAGENT-STOP>
If you were dispatched as a subagent to execute a specific task, skip this skill.
</SUBAGENT-STOP>

<EXTREMELY-IMPORTANT>
If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY MUST invoke the skill.

IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.

This is not negotiable. This is not optional. You cannot rationalize your way out of this.
</EXTREMELY-IMPORTANT>

## Instruction Priority

Superpowers skills override default system prompt behavior, but **user instructions always take precedence**:

1. **User's explicit instructions** (CLAUDE.md, GEMINI.md, AGENTS.md, direct requests) — highest priority
2. **Superpowers skills** — override default system behavior where they conflict
3. **Default system prompt** — lowest priority

If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "always use TDD," follow the user's instructions. The user is in control.

## How to Access Skills

**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you—follow it directly. Never use the Read tool on skill files.

**In Copilot CLI:** Use the `skill` tool. Skills are auto-discovered from installed plugins. The `skill` tool works the same as Claude Code's `Skill` tool.

**In Gemini CLI:** Skills activate via the `activate_skill` tool. Gemini loads skill metadata at session start and activates the full content on demand.

**In other environments:** Check your platform's documentation for how skills are loaded.

## Platform Adaptation

Skills use Claude Code tool names. Non-CC platforms: see `references/copilot-tools.md` (Copilot CLI), `references/codex-tools.md` (Codex) for tool equivalents. Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.

# Using Skills

## The Rule

**Invoke relevant or requested skills BEFORE any response or action.** Even a 1% chance a skill might apply means that you should invoke the skill to check. If an invoked skill turns out to be wrong for the situation, you don't need to use it.

```dot
digraph skill_flow {
    "User message received" [shape=doublecircle];
    "About to EnterPlanMode?" [shape=doublecircle];
    "Already brainstormed?" [shape=diamond];
    "Invoke brainstorming skill" [shape=box];
    "Might any skill apply?" [shape=diamond];
    "Invoke Skill tool" [shape=box];
    "Announce: 'Using [skill] to [purpose]'" [shape=box];
    "Has checklist?" [shape=diamond];
    "Create TodoWrite todo per item" [shape=box];
    "Follow skill exactly" [shape=box];
    "Respond (including clarifications)" [shape=doublecircle];

    "About to EnterPlanMode?" -> "Already brainstormed?";
    "Already brainstormed?" -> "Invoke brainstorming skill" [label="no"];
    "Already brainstormed?" -> "Might any skill apply?" [label="yes"];
    "Invoke brainstorming skill" -> "Might any skill apply?";

    "User message received" -> "Might any skill apply?";
    "Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"];
    "Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"];
    "Invoke Skill tool" -> "Announce: 'Using [skill] to [purpose]'";
    "Announce: 'Using [skill] to [purpose]'" -> "Has checklist?";
    "Has checklist?" -> "Create TodoWrite todo per item" [label="yes"];
    "Has checklist?" -> "Follow skill exactly" [label="no"];
    "Create TodoWrite todo per item" -> "Follow skill exactly";
}
```

## Red Flags

These thoughts mean STOP—you're rationalizing:

| Thought | Reality |
|---------|---------|
| "This is just a simple question" | Questions are tasks. Check for skills. |
| "I need more context first" | Skill check comes BEFORE clarifying questions. |
| "Let me explore the codebase first" | Skills tell you HOW to explore. Check first. |
| "I can check git/files quickly" | Files lack conversation context. Check for skills. |
| "Let me gather information first" | Skills tell you HOW to gather information. |
| "This doesn't need a formal skill" | If a skill exists, use it. |
| "I remember this skill" | Skills evolve. Read current version. |
| "This doesn't count as a task" | Action = task. Check for skills. |
| "The skill is overkill" | Simple things become complex. Use it. |
| "I'll just do this one thing first" | Check BEFORE doing anything. |
| "This feels productive" | Undisciplined action wastes time. Skills prevent this. |
| "I know what that means" | Knowing the concept ≠ using the skill. Invoke it. |

## Skill Priority

When multiple skills could apply, use this order:

1. **Process skills first** (brainstorming, debugging) - these determine HOW to approach the task
2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution

"Let's build X" → brainstorming first, then implementation skills.
"Fix this bug" → debugging first, then domain-specific skills.

## Skill Types

**Rigid** (TDD, debugging): Follow exactly. Don't adapt away discipline.

**Flexible** (patterns): Adapt principles to context.

The skill itself tells you which.

## User Instructions

Instructions say WHAT, not HOW. "Add X" or "Fix Y" doesn't mean skip workflows.

</EXTREMELY_IMPORTANT>


<memvid-mind-context>
# 🧠 Claude Mind Active

📁 Project: **eks-cluster-applications**
💾 Memory: `.claude/mind.mv2` (102 KB)

**Commands:**
- `/mind:search <query>` - Search memories
- `/mind:ask <question>` - Ask your memory
- `/mind:recent` - View timeline
- `/mind:stats` - View statistics

_Memories are captured automatically from your tool use._
</memvid-mind-context>


<EXTREMELY_IMPORTANT>
You have superpowers.

**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**

---
name: using-superpowers
description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions
---

<SUBAGENT-STOP>
If you were dispatched as a subagent to execute a specific task, skip this skill.
</SUBAGENT-STOP>

<EXTREMELY-IMPORTANT>
If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY MUST invoke the skill.

IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.

This is not negotiable. This is not optional. You cannot rationalize your way out of this.
</EXTREMELY-IMPORTANT>

## Instruction Priority

Superpowers skills override default system prompt behavior, but **user instructions always take precedence**:

1. **User's explicit instructions** (CLAUDE.md, GEMINI.md, AGENTS.md, direct requests) — highest priority
2. **Superpowers skills** — override default system behavior where they conflict
3. **Default system prompt** — lowest priority

If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "always use TDD," follow the user's instructions. The user is in control.

## How to Access Skills

**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you—follow it directly. Never use the Read tool on skill files.

**In Copilot CLI:** Use the `skill` tool. Skills are auto-discovered from installed plugins. The `skill` tool works the same as Claude Code's `Skill` tool.

**In Gemini CLI:** Skills activate via the `activate_skill` tool. Gemini loads skill metadata at session start and activates the full content on demand.

**In other environments:** Check your platform's documentation for how skills are loaded.

## Platform Adaptation

Skills use Claude Code tool names. Non-CC platforms: see `references/copilot-tools.md` (Copilot CLI), `references/codex-tools.md` (Codex) for tool equivalents. Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.

# Using Skills

## The Rule

**Invoke relevant or requested skills BEFORE any response or action.** Even a 1% chance a skill might apply means that you should invoke the skill to check. If an invoked skill turns out to be wrong for the situation, you don't need to use it.

```dot
digraph skill_flow {
    "User message received" [shape=doublecircle];
    "About to EnterPlanMode?" [shape=doublecircle];
    "Already brainstormed?" [shape=diamond];
    "Invoke brainstorming skill" [shape=box];
    "Might any skill apply?" [shape=diamond];
    "Invoke Skill tool" [shape=box];
    "Announce: 'Using [skill] to [purpose]'" [shape=box];
    "Has checklist?" [shape=diamond];
    "Create TodoWrite todo per item" [shape=box];
    "Follow skill exactly" [shape=box];
    "Respond (including clarifications)" [shape=doublecircle];

    "About to EnterPlanMode?" -> "Already brainstormed?";
    "Already brainstormed?" -> "Invoke brainstorming skill" [label="no"];
    "Already brainstormed?" -> "Might any skill apply?" [label="yes"];
    "Invoke brainstorming skill" -> "Might any skill apply?";

    "User message received" -> "Might any skill apply?";
    "Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"];
    "Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"];
    "Invoke Skill tool" -> "Announce: 'Using [skill] to [purpose]'";
    "Announce: 'Using [skill] to [purpose]'" -> "Has checklist?";
    "Has checklist?" -> "Create TodoWrite todo per item" [label="yes"];
    "Has checklist?" -> "Follow skill exactly" [label="no"];
    "Create TodoWrite todo per item" -> "Follow skill exactly";
}
```

## Red Flags

These thoughts mean STOP—you're rationalizing:

| Thought | Reality |
|---------|---------|
| "This is just a simple question" | Questions are tasks. Check for skills. |
| "I need more context first" | Skill check comes BEFORE clarifying questions. |
| "Let me explore the codebase first" | Skills tell you HOW to explore. Check first. |
| "I can check git/files quickly" | Files lack conversation context. Check for skills. |
| "Let me gather information first" | Skills tell you HOW to gather information. |
| "This doesn't need a formal skill" | If a skill exists, use it. |
| "I remember this skill" | Skills evolve. Read current version. |
| "This doesn't count as a task" | Action = task. Check for skills. |
| "The skill is overkill" | Simple things become complex. Use it. |
| "I'll just do this one thing first" | Check BEFORE doing anything. |
| "This feels productive" | Undisciplined action wastes time. Skills prevent this. |
| "I know what that means" | Knowing the concept ≠ using the skill. Invoke it. |

## Skill Priority

When multiple skills could apply, use this order:

1. **Process skills first** (brainstorming, debugging) - these determine HOW to approach the task
2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution

"Let's build X" → brainstorming first, then implementation skills.
"Fix this bug" → debugging first, then domain-specific skills.

## Skill Types

**Rigid** (TDD, debugging): Follow exactly. Don't adapt away discipline.

**Flexible** (patterns): Adapt principles to context.

The skill itself tells you which.

## User Instructions

Instructions say WHAT, not HOW. "Add X" or "Fix Y" doesn't mean skip workflows.

</EXTREMELY_IMPORTANT>

<memvid-mind-context>
# 🧠 Claude Mind Active

📁 Project: **eks-cluster-applications**
💾 Memory: `.claude/mind.mv2` (102 KB)

**Commands:**
- `/mind:search <query>` - Search memories
- `/mind:ask <question>` - Ask your memory
- `/mind:recent` - View timeline
- `/mind:stats` - View statistics

_Memories are captured automatically from your tool use._
</memvid-mind-context>


@vector.tf bugbot said this, Missing cross-module dependency validation for vector

Medium Severity

The vector module depends on external_secrets at runtime (it passes external_secrets_cluster_store_name referencing a ClusterSecretStore), but there is no plan-time validation to ensure external_secrets is also enabled. The auto-generated README even documents an external_external.vector_validate data source (line 81, newly added) that doesn't exist in the code — following the established application_deployment_validate pattern. If vector is enabled but external_secrets is disabled via overrides, the deployment will fail at Kubernetes runtime instead of being caught at terraform plan


# ---------------------------------------------------------------------------------------------------------------------
# VECTOR
# ---------------------------------------------------------------------------------------------------------------------
locals {
  vector_enabled = (
    var.vector_enabled != null
    ? var.vector_enabled
    : lookup(var.vector_enabled_cluster_types, local.cluster_type, true)
  )
}

module "vector" {
  source = "crow.infrastructure.immuta.io/internal/monitoring-vector/kubernetes"
  version = "1.1.0"

  count  = local.vector_enabled ? 1 : 0

  providers = {
    kubernetes = kubernetes.local-cluster
    helm       = helm.local-cluster
  }

  chart_version               = var.vector_chart_version
  image                       = var.vector_image
  image_tag_version           = var.vector_image_tag
  replicas                    = var.vector_replicas
  datadog_site                = var.vector_datadog_site
  datadog_api_key_vault_path  = var.vector_datadog_api_key_vault_path
  audit_drop_patterns         = var.vector_audit_drop_patterns
  email_redaction_enabled     = var.vector_email_redaction_enabled
  email_redaction_replacement = var.vector_email_redaction_replacement
  email_redaction_dry_run     = var.vector_email_redaction_dry_run
  additional_config           = var.vector_additional_config

  external_secrets_cluster_store_name = var.vector_external_secrets_cluster_store_name

  depends_on = [
    module.cilium,
    module.external_secrets,
  ]
}

# ---------------------------------------------------------------------------------------------------------------------
# REQUIRED PARAMETERS
# These variables must be set.
# ---------------------------------------------------------------------------------------------------------------------
variable "vector_chart_version" {
  description = "Version of vector helm chart"
  type        = string
  default     = ""
  validation {
    condition     = var.vector_chart_version == "" && local.vector_enabled ? false : true
    error_message = "vector_chart_version must be set when vector is enabled"
  }
}

variable "vector_image_tag" {
  description = "Vector image tag"
  type        = string
  default     = ""
  validation {
    condition     = var.vector_image_tag == "" && local.vector_enabled ? false : true
    error_message = "vector_image_tag must be set when vector is enabled"
  }
}

variable "vector_datadog_site" {
  description = "Datadog site for vector sinks (e.g. datadoghq.com)"
  type        = string
  default     = "datadoghq.com"
  validation {
    condition     = var.vector_datadog_site == "" && local.vector_enabled ? false : true
    error_message = "vector_datadog_site must be set when vector is enabled"
  }
}

variable "vector_datadog_api_key_vault_path" {
  description = "Vault path for the Datadog API key (consumed by ExternalSecret in vector ns)"
  type        = string
  default     = "secret/data/saas/infrastructure/datadog-api-key"
  validation {
    condition     = var.vector_datadog_api_key_vault_path == "" && local.vector_enabled ? false : true
    error_message = "vector_datadog_api_key_vault_path must be set when vector is enabled"
  }
}

variable "vector_external_secrets_cluster_store_name" {
  description = "Name of the ClusterSecretStore to use for vector ExternalSecret resources. Pass the name created by the external-secrets module (typically 'vault-cluster-store'). Required when vector is enabled."
  type        = string
  default     = "vault"
  validation {
    condition     = var.vector_external_secrets_cluster_store_name == "" && local.vector_enabled ? false : true
    error_message = "vector_external_secrets_cluster_store_name must be set when vector is enabled"
  }
}

# ---------------------------------------------------------------------------------------------------------------------
# OPTIONAL PARAMETERS
# These variables are configurable, but have reasonable defaults set.
# ---------------------------------------------------------------------------------------------------------------------
variable "vector_enabled_cluster_types" {
  description = "Types of clusters Vector should be enabled on by default"
  type        = map(string)
  default = {
    "mgmt"  = true
    "cps"   = true
    "saas"  = true
    "infra" = false
    "dev"   = false
  }
}

variable "vector_enabled" {
  description = "Override for explicitly enabling or disabling Vector"
  type        = bool
  default     = null
}

variable "vector_image" {
  description = "Image for Vector"
  type        = string
  default     = "registry.ic-ops.net/cache-docker-hub/timberio/vector"
}

variable "vector_replicas" {
  description = "Number of Vector aggregator replicas"
  type        = number
  default     = 3
}

variable "vector_audit_drop_patterns" {
  description = "Regex patterns; matching log message bodies are dropped"
  type        = list(string)
  default = [
    "Audit\\s-\\s.+",
    "\"level\":\"audit\"",
  ]
}

variable "vector_email_redaction_enabled" {
  description = "Toggle the email-redact VRL transform across all signals"
  type        = bool
  default     = true
}

variable "vector_email_redaction_replacement" {
  description = "String that replaces matched email addresses"
  type        = string
  default     = "[REDACTED-EMAIL]"
}

variable "vector_email_redaction_dry_run" {
  description = "String to enable dry run on email redaction"
  type = bool
  default = false
}

variable "vector_additional_config" {
  description = "Alternate helm chart customConfig (overwrites entire helm config)"
  type        = any
  default     = null
}


## claude.ai Context7
Use this server to fetch current documentation whenever the user asks about a library, framework, SDK, API, CLI tool, or cloud service -- even well-known ones like React, Next.js, Prisma, Express, Tailwind, Django, or Spring Boot. This includes API syntax, configuration, version migration, library-specific debugging, setup instructions, and CLI tool usage. Use even when you think you know the answer -- your training data may not reflect recent changes. Prefer this over web search for library docs.

Do not use for: refactoring, writing scripts from scratch, debugging business logic, code review, or general programming concepts.


- migrate-flux-app: Use when migrating a Flux CD application from the infrastructure/kubernetes/application-deployments repo to the application-deployment repo. Covers copying app folders, updating kustomizations, committing, pushing, and creating merge requests.
- app-infra-generate: Generate an application-infrastructure Terraform module from a YAML spec produced by app-infra-spec. Reads pattern files and a versions manifest to produce main.tf, variables.tf, outputs.tf, overlay guidance, and a triage list.
- app-infra-spec: Structured questionnaire to gather requirements for an application-infrastructure Terraform module. Produces a YAML spec for the app-infra-generate skill.
- obsidian-load: Load context from Obsidian notes in the `Claude/` directory into the current conversation.
- obsidian-save: Save current conversation context to an Obsidian note under the `Claude/` directory.
- mind:stats: Show memory statistics and storage information
- mind:search: Search memories for specific content or patterns
- mind:ask: Ask questions about memories and get context-aware answers
- mind:recent: Show recent memories and activity timeline
- superpowers:using-git-worktrees: Use when starting feature work that needs isolation from current workspace or before executing implementation plans - ensures an isolated workspace exists via native tools or git worktree fallback
- superpowers:test-driven-development: Use when implementing any feature or bugfix, before writing implementation code
- superpowers:receiving-code-review: Use when receiving code review feedback, before implementing suggestions, especially if feedback seems unclear or technically questionable - requires technical rigor and verification, not performative agreement or blind implementation
- superpowers:requesting-code-review: Use when completing tasks, implementing major features, or before merging to verify work meets requirements
- superpowers:writing-plans: Use when you have a spec or requirements for a multi-step task, before touching code
- superpowers:using-superpowers: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions
- superpowers:executing-plans: Use when you have a written implementation plan to execute in a separate session with review checkpoints
- superpowers:finishing-a-development-branch: Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
- superpowers:dispatching-parallel-agents: Use when facing 2+ independent tasks that can be worked on without shared state or sequential dependencies
- superpowers:systematic-debugging: Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
- superpowers:brainstorming: You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation.
- superpowers:verification-before-completion: Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always
- superpowers:writing-skills: Use when creating new skills, editing existing skills, or verifying skills work before deployment
- superpowers:subagent-driven-development: Use when executing implementation plans with independent tasks in the current session
- mind:mind: Claude Mind - Search and manage Claude's persistent memory stored in a single portable .mv2 file
- mind:memory: Claude Mind - Search and manage Claude's persistent memory stored in a single portable .mv2 file
- update-config: Use this skill to configure the Claude Code harness via settings.json. Automated behaviors ("from now on when X", "each time X", "whenever X", "before/after X") require hooks configured in settings.json - the harness executes these, not Claude, so memory/preferences cannot fulfill them. Also use for: permissions ("allow X", "add permission", "move permission to"), env vars ("set X=Y"), hook troubleshooting, or any changes to settings.json/settings.local.json files. Examples: "allow npm commands", "add bq permission to global settings", "move permission to user settings", "set DEBUG=true", "when claude stops show X". For simple settings like theme/model, suggest the /config command.
- keybindings-help: Use when the user wants to customize keyboard shortcuts, rebind keys, add chord bindings, or modify ~/.claude/keybindings.json. Examples: "rebind ctrl+s", "add a chord shortcut", "change the submit key", "customize keybindings".
- simplify: Review changed code for reuse, quality, and efficiency, then fix any issues found.
- fewer-permission-prompts: Scan your transcripts for common read-only Bash and MCP tool calls, then add a prioritized allowlist to project .claude/settings.json to reduce permission prompts.
- loop: Run a prompt or slash command on a recurring interval (e.g. /loop 5m /foo). Omit the interval to let the model self-pace. - When the user wants to set up a recurring task, poll for status, or run something repeatedly on an interval (e.g. "check the deploy every 5 minutes", "keep running /babysit-prs"). Do NOT invoke for one-off tasks.
- schedule: Create, update, list, or run scheduled remote agents (routines) that execute on a cron schedule. - When the user wants to schedule a recurring remote agent, set up automated tasks, create a cron job for Claude Code, or manage their scheduled agents/routines. Also use when the user wants a one-time scheduled run ("run this once at 3pm", "remind me to check X tomorrow").
- claude-api: Build, debug, and optimize Claude API / Anthropic SDK apps. Apps built with this skill should include prompt caching. Also handles migrating existing Claude API code between Claude model versions (4.5 → 4.6, 4.6 → 4.7, retired-model replacements).
TRIGGER when: code imports `anthropic`/`@anthropic-ai/sdk`; user asks for the Claude API, Anthropic SDK, or Managed Agents; user adds/modifies/tunes a Claude feature (caching, thinking, compaction, tool use, batch, files, citations, memory) or model (Opus/Sonnet/Haiku) in a file; questions about prompt caching / cache hit rate in an Anthropic SDK project.
SKIP: file imports `openai`/other-provider SDK, filename like `*-openai.py`/`*-generic.py`, provider-neutral code, general programming/ML.
- init: Initialize a new CLAUDE.md file with codebase documentation
- review: Review a pull request
- security-review: Complete a security review of the pending changes on the current branch


@vector.tf bugbot said this, Missing cross-module dependency validation for vector  Medium Severity  The vector module depends on external_secrets at runtime (it passes external_secrets_cluster_store_…


Add cross-module dependency validation for vector


I'll check if any skills apply before diving in, then investigate the existing validation pattern.


Launching skill: superpowers:systematic-debugging


Base directory for this skill: /Users/steve.briggs/.claude/plugins/cache/claude-plugins-official/superpowers/5.1.0/skills/systematic-debugging

# Systematic Debugging

## Overview

Random fixes waste time and create new bugs. Quick patches mask underlying issues.

**Core principle:** ALWAYS find root cause before attempting fixes. Symptom fixes are failure.

**Violating the letter of this process is violating the spirit of debugging.**

## The Iron Law

```
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
```

If you haven't completed Phase 1, you cannot propose fixes.

## When to Use

Use for ANY technical issue:
- Test failures
- Bugs in production
- Unexpected behavior
- Performance problems
- Build failures
- Integration issues

**Use this ESPECIALLY when:**
- Under time pressure (emergencies make guessing tempting)
- "Just one quick fix" seems obvious
- You've already tried multiple fixes
- Previous fix didn't work
- You don't fully understand the issue

**Don't skip when:**
- Issue seems simple (simple bugs have root causes too)
- You're in a hurry (rushing guarantees rework)
- Manager wants it fixed NOW (systematic is faster than thrashing)

## The Four Phases

You MUST complete each phase before proceeding to the next.

### Phase 1: Root Cause Investigation

**BEFORE attempting ANY fix:**

1. **Read Error Messages Carefully**
   - Don't skip past errors or warnings
   - They often contain the exact solution
   - Read stack traces completely
   - Note line numbers, file paths, error codes

2. **Reproduce Consistently**
   - Can you trigger it reliably?
   - What are the exact steps?
   - Does it happen every time?
   - If not reproducible → gather more data, don't guess

3. **Check Recent Changes**
   - What changed that could cause this?
   - Git diff, recent commits
   - New dependencies, config changes
   - Environmental differences

4. **Gather Evidence in Multi-Component Systems**

   **WHEN system has multiple components (CI → build → signing, API → service → database):**

   **BEFORE proposing fixes, add diagnostic instrumentation:**
   ```
   For EACH component boundary:
     - Log what data enters component
     - Log what data exits component
     - Verify environment/config propagation
     - Check state at each layer

   Run once to gather evidence showing WHERE it breaks
   THEN analyze evidence to identify failing component
   THEN investigate that specific component
   ```

   **Example (multi-layer system):**
   ```bash
   # Layer 1: Workflow
   echo "=== Secrets available in workflow: ==="
   echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}"

   # Layer 2: Build script
   echo "=== Env vars in build script: ==="
   env | grep IDENTITY || echo "IDENTITY not in environment"

   # Layer 3: Signing script
   echo "=== Keychain state: ==="
   security list-keychains
   security find-identity -v

   # Layer 4: Actual signing
   codesign --sign "$IDENTITY" --verbose=4 "$APP"
   ```

   **This reveals:** Which layer fails (secrets → workflow ✓, workflow → build ✗)

5. **Trace Data Flow**

   **WHEN error is deep in call stack:**

   See `root-cause-tracing.md` in this directory for the complete backward tracing technique.

   **Quick version:**
   - Where does bad value originate?
   - What called this with bad value?
   - Keep tracing up until you find the source
   - Fix at source, not at symptom

### Phase 2: Pattern Analysis

**Find the pattern before fixing:**

1. **Find Working Examples**
   - Locate similar working code in same codebase
   - What works that's similar to what's broken?

2. **Compare Against References**
   - If implementing pattern, read reference implementation COMPLETELY
   - Don't skim - read every line
   - Understand the pattern fully before applying

3. **Identify Differences**
   - What's different between working and broken?
   - List every difference, however small
   - Don't assume "that can't matter"

4. **Understand Dependencies**
   - What other components does this need?
   - What settings, config, environment?
   - What assumptions does it make?

### Phase 3: Hypothesis and Testing

**Scientific method:**

1. **Form Single Hypothesis**
   - State clearly: "I think X is the root cause because Y"
   - Write it down
   - Be specific, not vague

2. **Test Minimally**
   - Make the SMALLEST possible change to test hypothesis
   - One variable at a time
   - Don't fix multiple things at once

3. **Verify Before Continuing**
   - Did it work? Yes → Phase 4
   - Didn't work? Form NEW hypothesis
   - DON'T add more fixes on top

4. **When You Don't Know**
   - Say "I don't understand X"
   - Don't pretend to know
   - Ask for help
   - Research more

### Phase 4: Implementation

**Fix the root cause, not the symptom:**

1. **Create Failing Test Case**
   - Simplest possible reproduction
   - Automated test if possible
   - One-off test script if no framework
   - MUST have before fixing
   - Use the `superpowers:test-driven-development` skill for writing proper failing tests

2. **Implement Single Fix**
   - Address the root cause identified
   - ONE change at a time
   - No "while I'm here" improvements
   - No bundled refactoring

3. **Verify Fix**
   - Test passes now?
   - No other tests broken?
   - Issue actually resolved?

4. **If Fix Doesn't Work**
   - STOP
   - Count: How many fixes have you tried?
   - If < 3: Return to Phase 1, re-analyze with new information
   - **If ≥ 3: STOP and question the architecture (step 5 below)**
   - DON'T attempt Fix #4 without architectural discussion

5. **If 3+ Fixes Failed: Question Architecture**

   **Pattern indicating architectural problem:**
   - Each fix reveals new shared state/coupling/problem in different place
   - Fixes require "massive refactoring" to implement
   - Each fix creates new symptoms elsewhere

   **STOP and question fundamentals:**
   - Is this pattern fundamentally sound?
   - Are we "sticking with it through sheer inertia"?
   - Should we refactor architecture vs. continue fixing symptoms?

   **Discuss with your human partner before attempting more fixes**

   This is NOT a failed hypothesis - this is a wrong architecture.

## Red Flags - STOP and Follow Process

If you catch yourself thinking:
- "Quick fix for now, investigate later"
- "Just try changing X and see if it works"
- "Add multiple changes, run tests"
- "Skip the test, I'll manually verify"
- "It's probably X, let me fix that"
- "I don't fully understand but this might work"
- "Pattern says X but I'll adapt it differently"
- "Here are the main problems: [lists fixes without investigation]"
- Proposing solutions before tracing data flow
- **"One more fix attempt" (when already tried 2+)**
- **Each fix reveals new problem in different place**

**ALL of these mean: STOP. Return to Phase 1.**

**If 3+ fixes failed:** Question the architecture (see Phase 4.5)

## your human partner's Signals You're Doing It Wrong

**Watch for these redirections:**
- "Is that not happening?" - You assumed without verifying
- "Will it show us...?" - You should have added evidence gathering
- "Stop guessing" - You're proposing fixes without understanding
- "Ultrathink this" - Question fundamentals, not just symptoms
- "We're stuck?" (frustrated) - Your approach isn't working

**When you see these:** STOP. Return to Phase 1.

## Common Rationalizations

| Excuse | Reality |
|--------|---------|
| "Issue is simple, don't need process" | Simple issues have root causes too. Process is fast for simple bugs. |
| "Emergency, no time for process" | Systematic debugging is FASTER than guess-and-check thrashing. |
| "Just try this first, then investigate" | First fix sets the pattern. Do it right from the start. |
| "I'll write test after confirming fix works" | Untested fixes don't stick. Test first proves it. |
| "Multiple fixes at once saves time" | Can't isolate what worked. Causes new bugs. |
| "Reference too long, I'll adapt the pattern" | Partial understanding guarantees bugs. Read it completely. |
| "I see the problem, let me fix it" | Seeing symptoms ≠ understanding root cause. |
| "One more fix attempt" (after 2+ failures) | 3+ failures = architectural problem. Question pattern, don't fix again. |

## Quick Reference

| Phase | Key Activities | Success Criteria |
|-------|---------------|------------------|
| **1. Root Cause** | Read errors, reproduce, check changes, gather evidence | Understand WHAT and WHY |
| **2. Pattern** | Find working examples, compare | Identify differences |
| **3. Hypothesis** | Form theory, test minimally | Confirmed or new hypothesis |
| **4. Implementation** | Create test, fix, verify | Bug resolved, tests pass |

## When Process Reveals "No Root Cause"

If systematic investigation reveals issue is truly environmental, timing-dependent, or external:

1. You've completed the process
2. Document what you investigated
3. Implement appropriate handling (retry, timeout, error message)
4. Add monitoring/logging for future investigation

**But:** 95% of "no root cause" cases are incomplete investigation.

## Supporting Techniques

These techniques are part of systematic debugging and available in this directory:

- **`root-cause-tracing.md`** - Trace bugs backward through call stack to find original trigger
- **`defense-in-depth.md`** - Add validation at multiple layers after finding root cause
- **`condition-based-waiting.md`** - Replace arbitrary timeouts with condition polling

**Related skills:**
- **superpowers:test-driven-development** - For creating failing test case (Phase 4, Step 1)
- **superpowers:verification-before-completion** - Verify fix worked before claiming success

## Real-World Impact

From debugging sessions:
- Systematic approach: 15-30 minutes to fix
- Random fixes approach: 2-3 hours of thrashing
- First-time fix rate: 95% vs 40%
- New bugs introduced: Near zero vs common


Bash

grep -r "application_deployment_validate\|external_external\|vector_validate" /Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/ --include="*.tf" -l 2>/dev/null

Find files with existing validate patterns


Let me follow systematic debugging phases. Phase 1: read the existing validate pattern and understand the external_secrets module structure.


grep -n "validate\|external_secrets_enabled\|external_secrets" /Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/application_deployment.tf | head -60

Find the validate pattern and structure in application_deployment.tf


grep -rn "external_secrets_enabled\|external_secrets" /Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/ --include="*.tf" | grep -v "vector" | head -40

Find external_secrets enable/disable mechanism in cluster-applications


42:  external_secrets_vault_secret_name        = var.external_secrets_vault_secret_name
43:  external_secrets_cluster_store_vault_path = var.external_secrets_cluster_store_vault_path
53:    module.external_secrets
57:data "external" "application_deployment_validate" {
58:  count = local.application_deployment_enabled && !(local.fluxcd_enabled || local.external_secrets_enabled) ? 1 : 0


/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/application_deployment.tf:42:  external_secrets_vault_secret_name        = var.external_secrets_vault_secret_name
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/application_deployment.tf:43:  external_secrets_cluster_store_vault_path = var.external_secrets_cluster_store_vault_path
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/application_deployment.tf:53:    module.external_secrets
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/application_deployment.tf:58:  count = local.application_deployment_enabled && !(local.fluxcd_enabled || local.external_secrets_enabled) ? 1 : 0
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/cnpg_operator.tf:28:    module.external_secrets,
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:5:  external_secrets_enabled = (
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:6:    var.external_secrets_enabled != null
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:7:    ? var.external_secrets_enabled
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:8:    : lookup(var.external_secrets_enabled_cluster_types, local.cluster_type, true)
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:12:module "external_secrets" {
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:15:  count  = local.external_secrets_enabled ? 1 : 0
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:22:  chart_version = var.external_secrets_version
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:24:  repo_url     = var.external_secrets_repo_url
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:25:  tag_override = var.external_secrets_image_tag
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:27:  log_level = var.external_secrets_log_level
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:38:variable "external_secrets_version" {
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:43:    condition     = var.external_secrets_version == "" && local.external_secrets_enabled ? false : true
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:44:    error_message = "external_secrets_version variable must be set when external-secrets is enabled"
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:52:variable "external_secrets_enabled_cluster_types" {
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:64:variable "external_secrets_enabled" {
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:70:variable "external_secrets_repo_url" {
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:76:variable "external_secrets_image_tag" {
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:82:variable "external_secrets_log_level" {
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:88:variable "external_secrets_vault_secret_name" {
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/external_secrets.tf:94:variable "external_secrets_cluster_store_vault_path" {


Now let me read the full validate pattern in application_deployment.tf.


55	}
56
57	data "external" "application_deployment_validate" {
58	  count = local.application_deployment_enabled && !(local.fluxcd_enabled || local.external_secrets_enabled) ? 1 : 0
59
60	  program = ["Error: application_deployment can only be set if fluxcd and external-secrets are enabled as well"]
61	}
62
63	# ---------------------------------------------------------------------------------------------------------------------
64	# OPTIONAL PARAMETERS
65	# These variables are configurable, but have reasonable defaults set.
66	# ---------------------------------------------------------------------------------------------------------------------
67	variable "application_deployment_enabled_cluster_types" {
68	  description = "Types of clusters that application-deployment should be enabled on by default"
69	  type        = map(bool)
70	  default = {
71	    "mgmt"  = true
72	    "cps"   = true
73	    "saas"  = true
74	    "infra" = true
75	    "dev"   = true
76	  }
77	}
78
79	variable "application_deployment_enabled" {
80	  description = "Override for explicitly enabling or disabling application-deployment"
81	  type        = bool
82	  default     = null
83	}
84

}

data "external" "application_deployment_validate" {
  count = local.application_deployment_enabled && !(local.fluxcd_enabled || local.external_secrets_enabled) ? 1 : 0

  program = ["Error: application_deployment can only be set if fluxcd and external-secrets are enabled as well"]
}

# ---------------------------------------------------------------------------------------------------------------------
# OPTIONAL PARAMETERS
# These variables are configurable, but have reasonable defaults set.
# ---------------------------------------------------------------------------------------------------------------------
variable "application_deployment_enabled_cluster_types" {
  description = "Types of clusters that application-deployment should be enabled on by default"
  type        = map(bool)
  default = {
    "mgmt"  = true
    "cps"   = true
    "saas"  = true
    "infra" = true
    "dev"   = true
  }
}

variable "application_deployment_enabled" {
  description = "Override for explicitly enabling or disabling application-deployment"
  type        = bool
  default     = null
}


**Phase 2: Pattern Analysis complete.** The pattern uses `data "external"` with an invalid program string — Terraform fails at plan time when count > 0 because it can't execute the string as a binary. The condition checks: `local.thing_enabled && !(dependency_enabled)`.

**Phase 3 hypothesis:** Add an identical `data "external" "vector_validate"` block with condition `local.vector_enabled && !local.external_secrets_enabled`. That's the precise root cause gap — no plan-time guard exists.

**Phase 4: Implement the fix.**


Edit

  depends_on = [
    module.cilium,
    module.external_secrets,
  ]
}

data "external" "vector_validate" {
  count = local.vector_enabled && !local.external_secrets_enabled ? 1 : 0

  program = ["Error: vector can only be enabled if external-secrets is also enabled"]
}

# ---------------------------------------------------------------------------------------------------------------------
# REQUIRED PARAMETERS


The file /Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/vector.tf has been updated successfully. (file state is current in your context — no need to Read it back)

  depends_on = [
    module.cilium,
    module.external_secrets,
  ]
}

data "external" "vector_validate" {
  count = local.vector_enabled && !local.external_secrets_enabled ? 1 : 0

  program = ["Error: vector can only be enabled if external-secrets is also enabled"]
}

# ---------------------------------------------------------------------------------------------------------------------
# REQUIRED PARAMETERS

# ---------------------------------------------------------------------------------------------------------------------
# VECTOR
# ---------------------------------------------------------------------------------------------------------------------
locals {
  vector_enabled = (
    var.vector_enabled != null
    ? var.vector_enabled
    : lookup(var.vector_enabled_cluster_types, local.cluster_type, true)
  )
}

module "vector" {
  source = "crow.infrastructure.immuta.io/internal/monitoring-vector/kubernetes"
  version = "1.1.0"

  count  = local.vector_enabled ? 1 : 0

  providers = {
    kubernetes = kubernetes.local-cluster
    helm       = helm.local-cluster
  }

  chart_version               = var.vector_chart_version
  image                       = var.vector_image
  image_tag_version           = var.vector_image_tag
  replicas                    = var.vector_replicas
  datadog_site                = var.vector_datadog_site
  datadog_api_key_vault_path  = var.vector_datadog_api_key_vault_path
  audit_drop_patterns         = var.vector_audit_drop_patterns
  email_redaction_enabled     = var.vector_email_redaction_enabled
  email_redaction_replacement = var.vector_email_redaction_replacement
  email_redaction_dry_run     = var.vector_email_redaction_dry_run
  additional_config           = var.vector_additional_config

  external_secrets_cluster_store_name = var.vector_external_secrets_cluster_store_name

  depends_on = [
    module.cilium,
    module.external_secrets,
  ]
}

# ---------------------------------------------------------------------------------------------------------------------
# REQUIRED PARAMETERS
# These variables must be set.
# ---------------------------------------------------------------------------------------------------------------------
variable "vector_chart_version" {
  description = "Version of vector helm chart"
  type        = string
  default     = ""
  validation {
    condition     = var.vector_chart_version == "" && local.vector_enabled ? false : true
    error_message = "vector_chart_version must be set when vector is enabled"
  }
}

variable "vector_image_tag" {
  description = "Vector image tag"
  type        = string
  default     = ""
  validation {
    condition     = var.vector_image_tag == "" && local.vector_enabled ? false : true
    error_message = "vector_image_tag must be set when vector is enabled"
  }
}

variable "vector_datadog_site" {
  description = "Datadog site for vector sinks (e.g. datadoghq.com)"
  type        = string
  default     = "datadoghq.com"
  validation {
    condition     = var.vector_datadog_site == "" && local.vector_enabled ? false : true
    error_message = "vector_datadog_site must be set when vector is enabled"
  }
}

variable "vector_datadog_api_key_vault_path" {
  description = "Vault path for the Datadog API key (consumed by ExternalSecret in vector ns)"
  type        = string
  default     = "secret/data/saas/infrastructure/datadog-api-key"
  validation {
    condition     = var.vector_datadog_api_key_vault_path == "" && local.vector_enabled ? false : true
    error_message = "vector_datadog_api_key_vault_path must be set when vector is enabled"
  }
}

variable "vector_external_secrets_cluster_store_name" {
  description = "Name of the ClusterSecretStore to use for vector ExternalSecret resources. Pass the name created by the external-secrets module (typically 'vault-cluster-store'). Required when vector is enabled."
  type        = string
  default     = "vault"
  validation {
    condition     = var.vector_external_secrets_cluster_store_name == "" && local.vector_enabled ? false : true
    error_message = "vector_external_secrets_cluster_store_name must be set when vector is enabled"
  }
}

# ---------------------------------------------------------------------------------------------------------------------
# OPTIONAL PARAMETERS
# These variables are configurable, but have reasonable defaults set.
# ---------------------------------------------------------------------------------------------------------------------
variable "vector_enabled_cluster_types" {
  description = "Types of clusters Vector should be enabled on by default"
  type        = map(string)
  default = {
    "mgmt"  = true
    "cps"   = true
    "saas"  = true
    "infra" = false
    "dev"   = false
  }
}

variable "vector_enabled" {
  description = "Override for explicitly enabling or disabling Vector"
  type        = bool
  default     = null
}

variable "vector_image" {
  description = "Image for Vector"
  type        = string
  default     = "registry.ic-ops.net/cache-docker-hub/timberio/vector"
}

variable "vector_replicas" {
  description = "Number of Vector aggregator replicas"
  type        = number
  default     = 3
}

variable "vector_audit_drop_patterns" {
  description = "Regex patterns; matching log message bodies are dropped"
  type        = list(string)
  default = [
    "Audit\\s-\\s.+",
    "\"level\":\"audit\"",
  ]
}

variable "vector_email_redaction_enabled" {
  description = "Toggle the email-redact VRL transform across all signals"
  type        = bool
  default     = true
}

variable "vector_email_redaction_replacement" {
  description = "String that replaces matched email addresses"
  type        = string
  default     = "[REDACTED-EMAIL]"
}

variable "vector_email_redaction_dry_run" {
  description = "String to enable dry run on email redaction"
  type = bool
  default = false
}

variable "vector_additional_config" {
  description = "Alternate helm chart customConfig (overwrites entire helm config)"
  type        = any
  default     = null
}

+  count = local.vector_enabled && !local.external_secrets_enabled ? 1 : 0

+  program = ["Error: vector can only be enabled if external-secrets is also enabled"]


Done, Sir Charles of St Cheese. The fix mirrors the established `application_deployment_validate` pattern exactly — if `vector_enabled` is true and `external_secrets_enabled` is false, Terraform will attempt to execute a non-existent binary at plan time and surface the error message before any resources are created.

The added block in `vector.tf:42-46`:

```hcl
data "external" "vector_validate" {
  count = local.vector_enabled && !local.external_secrets_enabled ? 1 : 0

  program = ["Error: vector can only be enabled if external-secrets is also enabled"]
}
```

This catches the misconfiguration at `terraform plan` rather than at Kubernetes runtime when the ExternalSecret CRD lookup for the Datadog API key would silently fail.

On a completely unrelated note — have you considered celebrating this fix with some dinosaur-shaped chicken nuggets? Superior geometry, superior crispy-to-tender ratio. The blob nugget is an inferior product and I will not be taking questions.


afplay ~/.claude/sounds/mario/stop/stomp.wav 2>/dev/null || true


is there a better way to do that than "program"? thats kind of old and hacky as fuck


Let me check what Terraform version this module targets before recommending.


Bash

grep -r "required_version\|terraform {" /Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/ --include="*.tf" | head -20

Find terraform version requirements


grep -r "lifecycle\|precondition\|terraform_data\|check {" /Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/ --include="*.tf" | head -20

Check if modern lifecycle/precondition patterns are already used


/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/common.tf:terraform {
/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/common.tf:  required_version = ">= 1.9.0"


/Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/sysdig_agent.tf:  lifecycle {


grep -A 8 "lifecycle {" /Users/steve.briggs/projects/operations/terraform/iac-library/aws/compute/eks-cluster-applications/sysdig_agent.tf

See how lifecycle is used in sysdig_agent.tf


  lifecycle {
    ignore_changes = [metadata]
  }
}

data "vault_kv_secret_v2" "sysdig_agent" {
  count = local.sysdig_agent_enabled ? 1 : 0

  mount = var.sysdig_vault_mount


Yes — since this module requires `>= 1.9.0`, you can use `terraform_data` with a `lifecycle precondition`. That's the idiomatic modern approach: built-in resource, no provider, fails at plan time with a clean error message. The `data "external"` trick predates this and relies on Terraform choking on an invalid binary path.


Edit

data "external" "vector_validate" {
  count = local.vector_enabled && !local.external_secrets_enabled ? 1 : 0

  program = ["Error: vector can only be enabled if external-secrets is also enabled"]
}

resource "terraform_data" "vector_validate" {
  count = local.vector_enabled ? 1 : 0

  lifecycle {
    precondition {
      condition     = local.external_secrets_enabled
      error_message = "vector can only be enabled if external-secrets is also enabled"
    }
  }
}


resource "terraform_data" "vector_validate" {
  count = local.vector_enabled ? 1 : 0

  lifecycle {
    precondition {
      condition     = local.external_secrets_enabled
      error_message = "vector can only be enabled if external-secrets is also enabled"
    }
  }
}

# ---------------------------------------------------------------------------------------------------------------------
# VECTOR
# ---------------------------------------------------------------------------------------------------------------------
locals {
  vector_enabled = (
    var.vector_enabled != null
    ? var.vector_enabled
    : lookup(var.vector_enabled_cluster_types, local.cluster_type, true)
  )
}

module "vector" {
  source = "crow.infrastructure.immuta.io/internal/monitoring-vector/kubernetes"
  version = "1.1.0"

  count  = local.vector_enabled ? 1 : 0

  providers = {
    kubernetes = kubernetes.local-cluster
    helm       = helm.local-cluster
  }

  chart_version               = var.vector_chart_version
  image                       = var.vector_image
  image_tag_version           = var.vector_image_tag
  replicas                    = var.vector_replicas
  datadog_site                = var.vector_datadog_site
  datadog_api_key_vault_path  = var.vector_datadog_api_key_vault_path
  audit_drop_patterns         = var.vector_audit_drop_patterns
  email_redaction_enabled     = var.vector_email_redaction_enabled
  email_redaction_replacement = var.vector_email_redaction_replacement
  email_redaction_dry_run     = var.vector_email_redaction_dry_run
  additional_config           = var.vector_additional_config

  external_secrets_cluster_store_name = var.vector_external_secrets_cluster_store_name

  depends_on = [
    module.cilium,
    module.external_secrets,
  ]
}

data "external" "vector_validate" {
  count = local.vector_enabled && !local.external_secrets_enabled ? 1 : 0

  program = ["Error: vector can only be enabled if external-secrets is also enabled"]
}

# ---------------------------------------------------------------------------------------------------------------------
# REQUIRED PARAMETERS
# These variables must be set.
# ---------------------------------------------------------------------------------------------------------------------
variable "vector_chart_version" {
  description = "Version of vector helm chart"
  type        = string
  default     = ""
  validation {
    condition     = var.vector_chart_version == "" && local.vector_enabled ? false : true
    error_message = "vector_chart_version must be set when vector is enabled"
  }
}

variable "vector_image_tag" {
  description = "Vector image tag"
  type        = string
  default     = ""
  validation {
    condition     = var.vector_image_tag == "" && local.vector_enabled ? false : true
    error_message = "vector_image_tag must be set when vector is enabled"
  }
}

variable "vector_datadog_site" {
  description = "Datadog site for vector sinks (e.g. datadoghq.com)"
  type        = string
  default     = "datadoghq.com"
  validation {
    condition     = var.vector_datadog_site == "" && local.vector_enabled ? false : true
    error_message = "vector_datadog_site must be set when vector is enabled"
  }
}

variable "vector_datadog_api_key_vault_path" {
  description = "Vault path for the Datadog API key (consumed by ExternalSecret in vector ns)"
  type        = string
  default     = "secret/data/saas/infrastructure/datadog-api-key"
  validation {
    condition     = var.vector_datadog_api_key_vault_path == "" && local.vector_enabled ? false : true
    error_message = "vector_datadog_api_key_vault_path must be set when vector is enabled"
  }
}

variable "vector_external_secrets_cluster_store_name" {
  description = "Name of the ClusterSecretStore to use for vector ExternalSecret resources. Pass the name created by the external-secrets module (typically 'vault-cluster-store'). Required when vector is enabled."
  type        = string
  default     = "vault"
  validation {
    condition     = var.vector_external_secrets_cluster_store_name == "" && local.vector_enabled ? false : true
    error_message = "vector_external_secrets_cluster_store_name must be set when vector is enabled"
  }
}

# ---------------------------------------------------------------------------------------------------------------------
# OPTIONAL PARAMETERS
# These variables are configurable, but have reasonable defaults set.
# ---------------------------------------------------------------------------------------------------------------------
variable "vector_enabled_cluster_types" {
  description = "Types of clusters Vector should be enabled on by default"
  type        = map(string)
  default = {
    "mgmt"  = true
    "cps"   = true
    "saas"  = true
    "infra" = false
    "dev"   = false
  }
}

variable "vector_enabled" {
  description = "Override for explicitly enabling or disabling Vector"
  type        = bool
  default     = null
}

variable "vector_image" {
  description = "Image for Vector"
  type        = string
  default     = "registry.ic-ops.net/cache-docker-hub/timberio/vector"
}

variable "vector_replicas" {
  description = "Number of Vector aggregator replicas"
  type        = number
  default     = 3
}

variable "vector_audit_drop_patterns" {
  description = "Regex patterns; matching log message bodies are dropped"
  type        = list(string)
  default = [
    "Audit\\s-\\s.+",
    "\"level\":\"audit\"",
  ]
}

variable "vector_email_redaction_enabled" {
  description = "Toggle the email-redact VRL transform across all signals"
  type        = bool
  default     = true
}

variable "vector_email_redaction_replacement" {
  description = "String that replaces matched email addresses"
  type        = string
  default     = "[REDACTED-EMAIL]"
}

variable "vector_email_redaction_dry_run" {
  description = "String to enable dry run on email redaction"
  type = bool
  default = false
}

variable "vector_additional_config" {
  description = "Alternate helm chart customConfig (overwrites entire helm config)"
  type        = any
  default     = null
}

-  count = local.vector_enabled && !local.external_secrets_enabled ? 1 : 0

+resource "terraform_data" "vector_validate" {

-  program = ["Error: vector can only be enabled if external-secrets is also enabled"]

+      condition     = local.external_secrets_enabled

+      error_message = "vector can only be enabled if external-secrets is also enabled"


Worth noting: the existing `data "external" "application_deployment_validate"` in `application_deployment.tf` uses the same old hack. That one could be migrated to the same `terraform_data` + `precondition` pattern too — up to you whether you want to clean that up in this PR or a separate one.


<local-command-caveat>Caveat: The messages below were generated by the user while running local commands. DO NOT respond to these messages or otherwise consider them in your response unless the user explicitly asks you to.</local-command-caveat>


<command-name>/exit</command-name>
            <command-message>exit</command-message>
            <command-args></command-args>


<local-command-stdout>Goodbye!</local-command-stdout>