Skip to content

Detect deleted components in affected stacks#2063

Merged
aknysh merged 14 commits intomainfrom
aknysh/update-describe-affected-9
Feb 10, 2026
Merged

Detect deleted components in affected stacks#2063
aknysh merged 14 commits intomainfrom
aknysh/update-describe-affected-9

Conversation

@aknysh
Copy link
Copy Markdown
Member

@aknysh aknysh commented Feb 9, 2026

what

  • Deleted Component Detection: atmos describe affected now detects components and stacks that have been deleted in HEAD (current branch) compared to BASE (target branch)
  • New Output Fields: Added deleted (boolean) and deletion_type (string: component or stack) fields to the affected output schema
  • New Affected Reasons: Added deleted and deleted.stack as valid affected reasons
  • Integration Test Fixture: Added comprehensive test fixture at tests/fixtures/scenarios/atmos-describe-affected-deleted-detection/
  • Bug Fix: Fixed issue where stacks that only exist in BASE (not HEAD) were not being discovered during comparison - the code now re-scans BASE directory for stack config files instead of just converting HEAD paths
  • Documentation: Updated describe-affected.mdx with new fields, reasons, and CI/CD workflow examples
  • GitHub Actions Guide: Added new section in affected-stacks.mdx for destroy workflow integration
  • Blog Post: Added changelog entry announcing the feature
  • Roadmap: Updated CI/CD initiative with shipped milestone (progress: 80%)

why

  • Resource Leaks: Previously, when components or stacks were removed from configuration, CI/CD pipelines had no automated way to detect these deletions and trigger terraform destroy
  • Manual Destruction Required: Users had to manually identify and destroy removed components, which was error-prone and could lead to orphaned cloud resources
  • Incomplete CI/CD: Pipelines couldn't fully automate the infrastructure lifecycle - they could only handle creation and modification, not deletion
  • Audit Gaps: No automated tracking of what infrastructure was removed from configuration

How It Works

The algorithm now performs a second pass over BASE stacks to detect deletions:

  1. For each stack in BASE:

    • If stack doesn't exist in HEAD → all components marked as deleted.stack
    • If stack exists in HEAD → check each component
      • If component doesn't exist in HEAD → marked as deleted
  2. Abstract components (metadata.type: abstract) are not reported as deleted since they are blueprints and not provisioned

CI/CD Integration

Users can now separate apply and destroy workflows:

# Get modified components (for apply)
atmos describe affected --query '[.[] | select(.deleted != true)]'

# Get deleted components (for destroy)
atmos describe affected --query '[.[] | select(.deleted == true)]'

Test Coverage

  • 8 unit tests for deletion detection logic covering:

    • Component deleted from stack
    • Entire stack deleted
    • Abstract components not reported
    • Stack filter support
    • Multiple component types
    • Edge cases (no components section, no deletions)
  • 2 integration tests using new fixture:

    • TestDescribeAffectedDeletedComponentDetection
    • TestDescribeAffectedDeletedComponentFiltering

references

  • PRD: docs/prd/describe-affected-deleted-detection.md
  • Related to CI/CD simplification initiative on roadmap

Summary by CodeRabbit

  • New Features

    • Detects deleted components and stacks in describe-affected; adds two output fields: deleted and deletion_type.
  • Documentation

    • Added PRD, blog post, CLI docs and CI/CD examples describing deleted-detection and destruction workflows.
  • Tests

    • Added unit/integration tests and fixtures covering deletion scenarios, filtering, and abstract-component behavior.
  • Chores

    • Bumped toolchain/dependencies and refreshed NOTICE license entries.
  • Mocks

    • Added telemetry mock method to support feature-flag checks.
  • Errors

    • Introduced a new sentinel error for no stack manifests found.

aknysh and others added 6 commits February 8, 2026 20:28
Add automatic detection of components and stacks that have been deleted
in the current branch compared to the target branch. This enables CI/CD
pipelines to trigger terraform destroy workflows for removed infrastructure.

Changes:
- Add Deleted and DeletionType fields to schema.Affected struct
- Add detectDeletedComponents function to find deleted components
- Add new affected reasons: deleted, deleted.stack
- Add deletion types: component, stack
- Skip abstract components (not provisioned)
- Add 8 unit tests for deletion detection scenarios
- Regenerate posthog mock for new Client interface method

Documentation:
- Update describe-affected.mdx with new fields and examples
- Update affected-stacks.mdx GitHub Actions integration guide
- Add blog post for the new feature
- Update roadmap with shipped milestone

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@aknysh aknysh requested a review from a team as a code owner February 9, 2026 13:35
@aknysh aknysh added the minor New features that do not break anything label Feb 9, 2026
@github-actions github-actions bot added the size/xl Extra large size PR label Feb 9, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 9, 2026

🚀 Go Version Change Detected

This PR changes the Go version:

  • Base branch (main): 1.25.2
  • This PR: 1.25.5
  • Change: ⬆️ Upgrade

Tip

Upgrade Checklist

  • Verify all CI workflows pass with new Go version
  • Check for new language features that could be leveraged
  • Review release notes: https://go.dev/doc/go1.25
  • Update .tool-versions if using asdf
  • Update Dockerfile Go version if applicable

This is an automated comment from the Go Version Check action.

@aknysh aknysh self-assigned this Feb 9, 2026
@mergify
Copy link
Copy Markdown

mergify bot commented Feb 9, 2026

Warning

This PR exceeds the recommended limit of 1,000 lines.

Large PRs are difficult to review and may be rejected due to their size.

Please verify that this PR does not address multiple issues.
Consider refactoring it into smaller, more focused PRs to facilitate a smoother review process.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 9, 2026

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 11 package(s) with unknown licenses.
See the Details below.

License Issues

go.mod

PackageVersionLicenseIssue Type
cuelang.org/go0.15.4NullUnknown License
golang.org/x/oauth20.35.0NullUnknown License
golang.org/x/sys0.41.0NullUnknown License
golang.org/x/tools0.41.0NullUnknown License
github.com/cloudflare/circl1.6.3NullUnknown License
github.com/cyphar/filepath-securejoin0.6.1NullUnknown License
github.com/deckarep/golang-set/v22.8.0NullUnknown License
github.com/hashicorp/consul/api1.33.2NullUnknown License
github.com/hashicorp/vault/api1.22.0NullUnknown License
github.com/hashicorp/vault/api/auth/approle0.11.0NullUnknown License
github.com/klauspost/compress1.18.3NullUnknown License
Allowed Licenses: MIT, MIT-0, Apache-2.0, BSD-2-Clause, BSD-2-Clause-Views, BSD-3-Clause, ISC, MPL-2.0, 0BSD, Unlicense, CC0-1.0, CC-BY-3.0, CC-BY-4.0, CC-BY-SA-3.0, Python-2.0, OFL-1.1, LicenseRef-scancode-generic-cla, LicenseRef-scancode-unknown-license-reference, LicenseRef-scancode-unicode, LicenseRef-scancode-google-patent-license-golang

Scanned Files

  • go.mod

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds detection of deleted stacks and components to describe-affected by rescanning BASE vs HEAD, producing Affected entries with new deleted and deletion_type fields; integrates detection into aggregation, updates schema, tests, fixtures, docs, PRD, adds error sentinel, and bumps dependencies/NOTICE.

Changes

Cohort / File(s) Summary
Core Deletion Detection
internal/exec/describe_affected_deleted.go, internal/exec/describe_affected_components.go
New logic to detect and create Deleted Affected items; new unexported constants for deletion reasons/types and helpers to build metadata and integrations.
Aggregation Integration
internal/exec/describe_affected_utils.go, internal/exec/describe_affected_utils_parallel.go
Rescan BASE for stack manifests (use BASE paths for StackConfigFiles) and append deletions from detectDeletedComponents after parallel processing.
Schema & Telemetry Mock
pkg/schema/schema.go, pkg/telemetry/mock/mock_posthog_client.go
Adds Deleted (bool) and DeletionType (string) to Affected; extends PostHog mock with GetFeatureFlagResult.
Unit Tests
internal/exec/describe_affected_deleted_test.go, internal/exec/describe_affected_test.go
Extensive tests for deletion detection, filtering, abstract-component skipping, malformed data, component-path resolution and new test helpers.
Fixtures
tests/fixtures/scenarios/atmos-describe-affected-deleted-detection/*
New scenario fixtures (atmos.yaml and stack manifests) modeling deleted components and deleted stacks for tests.
Docs & PRD
docs/prd/describe-affected-deleted-detection.md, website/docs/cli/.../describe-affected.mdx, website/blog/2026-02-08-describe-affected-deleted-detection.mdx, website/docs/integrations/github-actions/affected-stacks.mdx
PRD, CLI docs, blog post and GH Actions guidance describing deletion detection, new output fields, filtering, and CI/CD patterns.
Config & Errors
errors/errors.go, pkg/config/utils.go
Adds exported ErrNoStackManifestsFound and wraps no-manifests case in FindAllStackConfigsInPathsForStack with that sentinel.
Metadata & Dependencies
go.mod, NOTICE, website/src/data/roadmap.js
Go toolchain and dependency bumps, NOTICE license URL updates and additions, and roadmap milestone added for deleted-component detection.
Misc Docs / Policies
CLAUDE.md
Adds path-handling/testing guidance for tests (use filepath.Join, normalize with filepath.ToSlash, avoid shell commands).

Sequence Diagram

sequenceDiagram
    participant CLI as describe-affected CLI
    participant Parallel as Parallel Processor
    participant Detect as detectDeletedComponents
    participant Remote as BASE (remoteStacks)
    participant Current as HEAD (currentStacks)
    participant Schema as Affected Schema

    CLI->>Parallel: compareStacks(Remote, Current, filter)
    Parallel->>Parallel: process per-stack diffs (mods)
    Parallel->>Detect: detectDeletedComponents(Remote, Current, filter)
    Detect->>Remote: iterate remote stacks
    alt stack missing in Current
        Detect->>Schema: processDeletedStack -> mark components deleted (deletion_type:"stack")
    else stack present
        Detect->>Current: compare component sets
        Detect->>Schema: processDeletedComponentsInStack -> mark missing components deleted (deletion_type:"component")
        Detect->>Schema: skip abstract components
    end
    Detect->>Parallel: return deleted Affected items
    Parallel->>CLI: append deletions to final affected list
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • osterman
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 96.15% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title clearly describes the main feature: detecting deleted components in affected stacks, which aligns with the primary change across the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch aknysh/update-describe-affected-9

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 9, 2026

Codecov Report

❌ Patch coverage is 87.91209% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.11%. Comparing base (aab4968) to head (43d241b).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/exec/describe_affected_deleted.go 93.42% 5 Missing and 5 partials ⚠️
internal/exec/describe_affected_utils.go 50.00% 6 Missing and 3 partials ⚠️
internal/exec/describe_affected_utils_parallel.go 77.77% 1 Missing and 1 partial ⚠️
pkg/config/utils.go 0.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2063      +/-   ##
==========================================
+ Coverage   76.09%   76.11%   +0.02%     
==========================================
  Files         797      798       +1     
  Lines       74649    74821     +172     
==========================================
+ Hits        56803    56949     +146     
- Misses      14300    14321      +21     
- Partials     3546     3551       +5     
Flag Coverage Δ
unittests 76.11% <87.91%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
errors/errors.go 100.00% <ø> (ø)
internal/exec/describe_affected_components.go 62.21% <ø> (ø)
pkg/list/extract/affected.go 97.93% <100.00%> (+0.04%) ⬆️
pkg/schema/schema.go 88.98% <ø> (ø)
pkg/config/utils.go 87.14% <0.00%> (ø)
internal/exec/describe_affected_utils_parallel.go 90.47% <77.77%> (-1.20%) ⬇️
internal/exec/describe_affected_utils.go 78.62% <50.00%> (-0.06%) ⬇️
internal/exec/describe_affected_deleted.go 93.42% <93.42%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

This PR introduces detection of deleted components and stacks in the describe-affected workflow by comparing BASE (target) and HEAD (current) states. It updates the schema with new fields, extends the detection pipeline for both sequential and parallel flows, adds comprehensive tests and fixtures, and includes documentation and blog post updates. Several Go dependencies are also bumped to newer versions.

Changes

Cohort / File(s) Summary
Deletion Detection Core
internal/exec/describe_affected_deleted.go, internal/exec/describe_affected_deleted_test.go
Implements detection logic for deleted components and stacks by iterating over BASE stacks and marking missing components in HEAD with appropriate deletion type (component vs stack), skipping abstract components. Includes comprehensive unit tests for single/multi-component deletions, stack filtering, and edge cases.
Schema & Constants
pkg/schema/schema.go, internal/exec/describe_affected_components.go
Adds Deleted (bool) and DeletionType (string) fields to Affected struct; introduces deletion-related constants (affectedReasonDeleted, affectedReasonDeletedStack, etc.) for tracking deletion reason and type metadata.
Pipeline Integration
internal/exec/describe_affected_utils.go, internal/exec/describe_affected_utils_parallel.go, internal/exec/describe_affected_test.go
Integrates deletion detection into both sequential and parallel describe-affected flows; updates BASE stack discovery logic to rescan remote directory instead of deriving from HEAD paths; adds integration tests verifying deletion detection and filtering by stack.
Test Fixtures
tests/fixtures/scenarios/atmos-describe-affected-deleted-detection/*
Adds new test scenario with Atmos YAML fixtures (atmos.yaml, staging/production stacks) simulating both component-level and stack-level deletions for verification.
Documentation
website/docs/cli/commands/describe/describe-affected.mdx, website/docs/integrations/github-actions/affected-stacks.mdx, website/blog/2026-02-08-describe-affected-deleted-detection.mdx
Documents new deleted and deletion_type fields, filtering examples for deleted vs modified components, CI/CD workflow patterns (separate apply/destroy), warnings on destructive operations, and edge cases (abstract components excluded).
Telemetry & Roadmap
pkg/telemetry/mock/mock_posthog_client.go, website/src/data/roadmap.js
Adds mock support for GetFeatureFlagResult method; updates roadmap CI/CD milestone progress (75→80) and ships new milestone for deleted component detection.
Dependency Updates
go.mod, NOTICE
Bumps Go version from 1.25.2 to 1.25.5; updates numerous direct and indirect dependencies (e.g., opentelemetry, k8s.io/client-go, various OAuth/API libraries) to newer patch/minor versions.

Sequence Diagram

sequenceDiagram
    participant CLI as Describe Affected CLI
    participant Detect as Detection Engine
    participant BASE as BASE Stacks
    participant HEAD as HEAD Stacks
    participant Schema as Affected Schema
    participant Output as Output

    CLI->>Detect: Start describe-affected with BASE & HEAD
    
    activate Detect
    Detect->>BASE: Load BASE stacks (remote)
    Detect->>HEAD: Load HEAD stacks (current)
    
    Note over Detect: Phase 1: Detect modifications<br/>(existing per-stack comparison)
    loop Per-stack modified comparison
        Detect->>BASE: Get stack components
        Detect->>HEAD: Get stack components
        Detect->>Schema: Create Affected items<br/>(modified=true)
    end
    
    Note over Detect: Phase 2: Detect deletions<br/>(iterate BASE, check against HEAD)
    loop Over BASE stacks
        alt Stack missing in HEAD
            Detect->>Schema: Mark all non-abstract<br/>components as deleted<br/>(deletion_type: stack)
        else Stack exists, check components
            loop Over BASE components
                alt Component missing in HEAD
                    Detect->>Schema: Mark component deleted<br/>(deletion_type: component)
                else Abstract component
                    Detect->>Detect: Skip (abstract)
                end
            end
        end
    end
    deactivate Detect
    
    Schema->>Output: Return combined affected list<br/>(modified + deleted)
    Output->>CLI: Display results with deleted flag
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

Suggested Reviewers

  • osterman
  • aknysh
  • jamengual
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main feature being added: deleted component and stack detection in the describe affected command.
Docstring Coverage ✅ Passed Docstring coverage is 95.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch aknysh/update-describe-affected-9

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@docs/prd/describe-affected-deleted-detection.md`:
- Around line 46-51: The PRD and implementation disagree: the code defines
affectedReasonDeleted = "deleted" and affectedReasonDeletedStack =
"deleted.stack" but there is no "deleted.component" or "component_instance" in
the implementation; update the PRD to match the code by replacing
`deleted.component` with `deleted` (or add a note that `deleted` covers
component deletions) and change the deletion types table to list only
`component` and `stack` (or `deleted`/`deleted.stack` as the canonical reason
strings), or alternatively add corresponding constants/handlers (e.g., a new
affectedReasonDeletedComponent = "deleted.component" and support for
"component_instance") if you prefer changing code instead of docs—refer to
affectedReasonDeleted, affectedReasonDeletedStack, `deleted.component`, and
`component_instance` when making the change.

In `@internal/exec/describe_affected_utils.go`:
- Around line 119-122: The current code swallows every error from
FindAllStackConfigsInPathsForStack by unconditionally setting
remoteStackConfigFilesAbsolutePaths = []string{}, which can hide real failures;
change the handling to detect the specific "no manifests found" condition (e.g.,
compare err to the package's sentinel like ErrNoManifests or inspect the error
message/type returned by FindAllStackConfigsInPathsForStack) and only set
remoteStackConfigFilesAbsolutePaths to an empty slice in that case, otherwise
propagate or return the unexpected error (or at minimum log it at debug via your
logger) so callers of the surrounding function in describe_affected_utils.go
receive real errors instead of silent success.
🧹 Nitpick comments (4)
website/blog/2026-02-08-describe-affected-deleted-detection.mdx (1)

110-118: Consider adding the same safety warning present in the docs.

The destroy job uses --auto-approve without a manual approval gate. The affected-stacks docs include a :::warning about reviewing deletions first. Worth adding a similar note here so readers of the blog post alone get the same guidance.

website/src/data/roadmap.js (1)

346-346: Missing pr field on the new milestone.

Other shipped milestones include a pr number for traceability. Consider adding pr: 2063 here.

Suggested fix
-        { label: 'Deleted component detection for destroy workflows', status: 'shipped', quarter: 'q1-2026', docs: '/cli/commands/describe/affected', changelog: 'describe-affected-deleted-detection', description: 'Automatically detect components and stacks that have been deleted in the current branch compared to the target branch. Enables CI/CD pipelines to trigger terraform destroy workflows for removed infrastructure.', category: 'featured', priority: 'high', benefits: 'CI/CD pipelines can now separate apply and destroy workflows automatically. No more orphaned cloud resources from removed components.' },
+        { label: 'Deleted component detection for destroy workflows', status: 'shipped', quarter: 'q1-2026', pr: 2063, docs: '/cli/commands/describe/affected', changelog: 'describe-affected-deleted-detection', description: 'Automatically detect components and stacks that have been deleted in the current branch compared to the target branch. Enables CI/CD pipelines to trigger terraform destroy workflows for removed infrastructure.', category: 'featured', priority: 'high', benefits: 'CI/CD pipelines can now separate apply and destroy workflows automatically. No more orphaned cloud resources from removed components.' },

As per coding guidelines, PRs labeled minor/major MUST update website/src/data/roadmap.js with milestone status, changelog link, PR link, and initiative progress percentage.

internal/exec/describe_affected_test.go (1)

1449-1449: Loose strings.Contains check could match unintended stacks.

The fallback strings.Contains(a.Stack, "production") is understandable for unprocessed templates, but in a larger fixture it could match stacks like "non-production-staging". Since the fixture is controlled this is fine for now, but a more precise regex or suffix match would be more robust.

internal/exec/describe_affected_deleted.go (1)

214-229: Deleted items don't populate optional metadata fields that non-deleted items do.

Affected items for non-deleted components set Environment from stack vars. Deleted items skip Namespace, Tenant, Environment, Stage, SpaceliftStack, AtlantisProject, and others. While these fields are optional (omitempty), downstream consumers filtering or grouping by tenant/environment for destroy operations might expect consistency.

The deletedItemParams provides access to the BASE component section's metadata—extracting and populating these fields would improve output completeness if other parts of the toolchain depend on them.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
NOTICE (1)

1-4: ⚠️ Potential issue | 🟡 Minor

Pipeline failure: NOTICE file is out of date.

The Dependency Review CI check is failing with: NOTICE file is out of date. Run './scripts/generate-notice.sh' locally and commit the changes. Since this file is programmatically generated, regenerate it to pass CI.

🤖 Fix all issues with AI agents
In `@docs/prd/describe-affected-deleted-detection.md`:
- Around line 46-51: Update the PRD to match the shipped implementation: replace
any mention of the non-existent reason `deleted.component` with the actual
reason `deleted`, and remove `component_instance` as a deletion type—only
document `component` and `stack` as supported deletion types (keep the table
rows/headers consistent with the implemented values `deleted`, `component`, and
`stack`).

In `@internal/exec/describe_affected_deleted.go`:
- Around line 136-140: The current branch incorrectly delegates to
processDeletedStack when currentComponentsSection is missing, which labels the
whole stack as deleted; instead detect this edge case and treat it as
"components removed" by iterating remoteComponentsSection's components and
emitting per-component deletions with deletion_type "component" and affected
"deleted" (or call a new helper like processDeletedComponents(stackName,
remoteComponentsSection, atmosConfig)); replace the processDeletedStack(...)
call in the currentComponentsSection nil branch with that per-component handling
so the stack is not marked as a deleted.stack.
- Around line 214-230: createDeletedAffectedItem currently omits context fields;
call GetContextFromVars(params.componentSection) inside
createDeletedAffectedItem (using the same pattern as non-deleted items), extract
Namespace, Tenant, Environment, and Stage from its return and assign them to
affected.Namespace, affected.Tenant, affected.Environment, and affected.Stage
before returning; reference the function name createDeletedAffectedItem, the
params struct deletedItemParams, and GetContextFromVars to locate where to add
these assignments.

In `@internal/exec/describe_affected_utils.go`:
- Around line 101-123: The code currently swallows all errors from
cfg.FindAllStackConfigsInPathsForStack and treats any failure as "all stacks
deleted"; change this so only the specific "no matches" sentinel error from the
cfg package is treated as an empty list (set remoteStackConfigFilesAbsolutePaths
= []string{}), and any other error is returned up the stack. Update the error
handling after the call to FindAllStackConfigsInPathsForStack to use
errors.Is(err, cfg.<sentinelErrName>) (or inspect the returned error type if cfg
provides a typed error) to detect the "no stack manifests" case; for all other
errors, return nil, nil, nil, err. Ensure references to
FindAllStackConfigsInPathsForStack, remoteStackConfigFilesAbsolutePaths, and
atmosConfig.StackConfigFilesAbsolutePaths remain unchanged.

In `@website/docs/integrations/github-actions/affected-stacks.mdx`:
- Around line 74-86: The destroy job currently runs atmos terraform destroy with
--auto-approve while the following warning advises manual review; update the
GitHub Actions workflow (the destroy job and its steps) to remove the
--auto-approve flag and/or add an explicit approval step (e.g., a manual
approval job or required reviewers via an environment) before the run step that
executes atmos terraform destroy ${{ matrix.component }} -s ${{ matrix.stack }}
so the workflow enforces human confirmation consistent with the warning.

In `@website/src/data/roadmap.js`:
- Line 346: The new roadmap milestone object with label 'Deleted component
detection for destroy workflows' is missing the required pr field; update that
milestone object (the entry with label 'Deleted component detection for destroy
workflows') to include pr: 'https://github.com/your-repo/pull/2063' (or the
canonical PR link for `#2063`) so it matches other milestones and satisfies the
guideline about including PR links in website/src/data/roadmap.js; keep the rest
of the fields unchanged and ensure the string format matches existing pr
entries.
🧹 Nitpick comments (4)
docs/prd/describe-affected-deleted-detection.md (1)

185-228: CI/CD example uses --auto-approve on destroy — worth a safety callout.

Line 227 shows atmos terraform destroy ... --auto-approve in the example workflow. This is fine as a reference, but a brief note recommending a manual approval gate (e.g., GitHub Environment protection rules) for production destroy workflows would strengthen the guidance.

internal/exec/describe_affected_test.go (1)

1447-1449: Loose production stack matching could catch unintended stacks.

strings.Contains(a.Stack, "production") would match any stack name containing "production" (e.g., "pre-production-us-east-1"). It works in this fixture since there's only one such stack, but it's fragile if the fixture grows.

Consider tightening to strings.HasSuffix or an exact match + the unprocessed template variant:

Proposed tightening
-		isProductionStack := a.Stack == "ue1-production" || strings.Contains(a.Stack, "production")
+		isProductionStack := a.Stack == "ue1-production" || strings.HasSuffix(a.Stack, "-production")
website/docs/cli/commands/describe/describe-affected.mdx (2)

1107-1107: Nit: "vs" → "vs." for American English.

Static analysis flagged this. In American English convention, abbreviations typically get a period.

-## Detecting Deleted Components for Destruction Workflows
+## Detecting Deleted Components for Destroy Workflows

Alternatively, just add the period: "Deleted vs. Modified Components" on line 1124.


1139-1186: CI/CD example is practical — one thing to note on the destroy step.

The --auto-approve on Line 1185 bypasses confirmation. The warning block on Lines 1188-1191 correctly flags this as irreversible. Consider adding a manual approval step in the example to reinforce the warning:

Suggested addition
   destroy:
     needs: detect-changes
     if: needs.detect-changes.outputs.deleted != '[]'
+    environment: production  # Requires manual approval
     strategy:

This would make the example more aligned with the "consider adding manual approval steps" guidance in the warning.

- Populate metadata fields (Namespace, Tenant, Environment, Stage) for
  deleted components from BASE vars section
- Add Spacelift stack and Atlantis project names for deleted Terraform
  components
- Add debug logging when BASE stack manifest discovery fails
- Fix PRD to match implementation (remove non-existent deleted.component
  reason and component_instance deletion type)
- Use strings.HasSuffix instead of strings.Contains in test
- Add safety warning to blog post about --auto-approve
- Add PR number to roadmap milestone

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@website/blog/2026-02-08-describe-affected-deleted-detection.mdx`:
- Around line 114-122: The CI example's destroy (and apply) matrix jobs rely on
repository files and atmos but omit a checkout and atmos install, so add an
actions/checkout step and the same atmos installation used elsewhere at the
start of the destroy job (and mirror into apply) before running atmos commands;
locate the destroy job and its steps (job name: destroy, matrix: include, step
running `atmos terraform destroy ${ matrix.component } -s ${ matrix.stack }
--auto-approve`) and insert an `actions/checkout` step plus the atmos install
step used in detect-changes/apply so the matrix runners have the repo and atmos
available.
🧹 Nitpick comments (2)
internal/exec/describe_affected_test.go (1)

1448-1451: HasSuffix("-production") could match unintended stacks.

The comment explains this handles unprocessed template names, which is fair. But HasSuffix(a.Stack, "-production") would also match stacks like non-production or pre-production. The test fixtures likely don't have such names, but this is fragile.

Consider a tighter check if the fixture set grows:

Suggestion
-		isProductionStack := a.Stack == "ue1-production" || strings.HasSuffix(a.Stack, "-production")
+		isProductionStack := a.Stack == "ue1-production" || strings.HasSuffix(a.Stack, "-production") || a.Stack == "production"

Or use a regex like \bproduction$ if needed. Fine for now given the controlled fixture set.

internal/exec/describe_affected_deleted.go (1)

240-265: populateDeletedItemMetadata uses mapstructure.Decode instead of cfg.GetContextFromVars.

The existing codebase uses cfg.GetContextFromVars(varsSection) to extract context from vars (see spacelift_utils.go:108, atlantis_utils.go:39). Using mapstructure.Decode directly works but diverges from the established pattern.

Consider using cfg.GetContextFromVars for consistency:

Suggestion
-	var context schema.Context
-	if err := mapstructure.Decode(varsSection, &context); err != nil {
-		// If decoding fails, skip metadata population but continue.
-		return
-	}
+	context := cfg.GetContextFromVars(varsSection)

This also removes the mapstructure import from this file.

- Add ErrNoStackManifestsFound sentinel error and use errors.Is() instead
  of string checking for proper error handling
- Use cfg.GetContextFromVars() instead of mapstructure.Decode for
  consistency with spacelift_utils.go and atlantis_utils.go
- Refactor processDeletedStack to use processAllComponentsAsDeleted helper
  with configurable deletion type/reason
- Fix edge case: stack exists but lacks components section now correctly
  uses deletion_type: "component" instead of "stack"
- Add environment protection and checkout steps to CI/CD examples
- Fix "vs" -> "vs." for American English
- Add exact "production" stack name check in test
- Use correct GitHub Action: cloudposse/github-action-setup-atmos@v2

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@docs/prd/describe-affected-deleted-detection.md`:
- Line 99: Replace the informal "vs" with the American English abbreviation
"vs." in the user-facing phrases identified (e.g., the sentence containing
"Users can filter the output using `--query` to separate modified vs deleted
components" and the phrase "moves vs deletes"); update those occurrences so they
read "vs." (with a period) to conform to the style convention.
- Around line 213-231: The apply and destroy jobs currently run atmos commands
on fresh runners without checking out the repo or installing Atmos; add initial
steps in the apply and destroy job definitions to (1) checkout the repository
using actions/checkout (or equivalent) and (2) install or set up the Atmos CLI
(e.g., use the official Atmos setup action or install via package manager/curl)
before the run: atmos terraform ... steps so the matrix-mounted ${
matrix.component } and ${ matrix.stack } commands execute successfully.

In `@internal/exec/describe_affected_deleted.go`:
- Around line 134-137: The //nolint rationale on the
processDeletedComponentsInStack function is missing a trailing period; update
the comment line (above processDeletedComponentsInStack) to end with a period
(e.g., "//nolint:funlen,revive // function-length: logic is straightforward,
splitting would reduce readability.") and apply the same fix to the other nolint
rationale comments in the same file (around lines referenced 151-209) so every
inline rationale sentence terminates with a period.

In `@website/docs/cli/commands/describe/describe-affected.mdx`:
- Around line 1143-1187: The apply and destroy jobs (job names "apply" and
"destroy") are missing repository checkout and Atmos CLI setup so their atmos
terraform commands will fail on fresh runners; add steps at the start of each
job to run actions/checkout@v4 (with fetch-depth: 0) and to install/configure
the Atmos CLI (a step that ensures atmos is on PATH) before the step that runs
"atmos terraform apply ${{ matrix.component }} -s ${{ matrix.stack }}" and
"atmos terraform destroy ${{ matrix.component }} -s ${{ matrix.stack }}
--auto-approve" respectively so the commands can execute successfully.
🧹 Nitpick comments (1)
website/docs/cli/commands/describe/describe-affected.mdx (1)

690-754: Documentation for deleted and deleted.stack affected reasons is thorough with good examples.

One minor note: these entries are wedged between file and folder in the <dl> list. Grouping deletion reasons at the end (after folder) might read more naturally since they represent a different category of change. Not blocking — just a thought.

- Fix TestDetectDeletedComponents_NoComponentsSection to expect
  deletion_type: "component" (not "stack") when stack exists but
  lacks components section
- Update PRD with complete CI/CD example (checkout + atmos setup)
- Add safety warning about --auto-approve in destroy workflows
- Fix "vs" to "vs." for American English consistency
- Improve nolint directive explanation for processDeletedComponentsInStack
- Update docs with complete CI/CD examples

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/cloudposse/atmos/issues/comments/3871846840","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds detection of deleted stacks and components to describe-affected by rescanning BASE vs HEAD, marking affected items with new deleted and deletion_type fields; integrates detection into aggregation, updates schema, tests, fixtures, docs, PRD, and bumps dependencies/NOTICE entries.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Core Deletion Detection** <br> `internal/exec/describe_affected_deleted.go`, `internal/exec/describe_affected_components.go`|New detection logic and helpers to generate Deleted Affected entries; new unexported deletion reason/type constants.|\n|**Aggregation Integration** <br> `internal/exec/describe_affected_utils.go`, `internal/exec/describe_affected_utils_parallel.go`|Rescan BASE for stack manifests, source StackConfigFiles from BASE, and append deletions via detectDeletedComponents after parallel processing.|\n|**Schema & Telemetry Mock** <br> `pkg/schema/schema.go`, `pkg/telemetry/mock/mock_posthog_client.go`|Adds `Deleted` (bool) and `DeletionType` (string) to Affected; adds mock GetFeatureFlagResult method.|\n|**Unit Tests** <br> `internal/exec/describe_affected_deleted_test.go`, `internal/exec/describe_affected_test.go`|Extensive unit tests for deletion detection, filtering, abstract-component skipping, and test helper additions.|\n|**Fixtures** <br> `tests/fixtures/scenarios/atmos-describe-affected-deleted-detection/*`|New scenario fixtures (atmos.yaml and stack manifests) modeling deleted components and deleted stacks for tests.|\n|**Docs & PRD** <br> `docs/prd/describe-affected-deleted-detection.md`, `website/docs/cli/.../describe-affected.mdx`, `website/blog/2026-02-08-describe-affected-deleted-detection.mdx`, `website/docs/integrations/github-actions/affected-stacks.mdx`|PRD, CLI docs, blog post and GH Actions guidance describing deletion detection, new output fields, filtering, and CI/CD patterns.|\n|**Config & Errors** <br> `errors/errors.go`, `pkg/config/utils.go`|Adds exported ErrNoStackManifestsFound and wraps no-manifests case in FindAllStackConfigsInPathsForStack with that sentinel.|\n|**Metadata & Dependencies** <br> `go.mod`, `NOTICE`, `website/src/data/roadmap.js`|Go toolchain and dependency bumps, NOTICE license URL updates, and roadmap milestone added for deleted-component detection.|\n\n## Sequence Diagram\n\n```mermaid\nsequenceDiagram\n    participant CLI as describe-affected CLI\n    participant Parallel as Parallel Processor\n    participant Detect as detectDeletedComponents\n    participant Remote as BASE (remoteStacks)\n    participant Current as HEAD (currentStacks)\n    participant Schema as Affected Schema\n\n    CLI->>Parallel: compareStacks(Remote, Current, filter)\n    Parallel->>Parallel: process per-stack diffs (mods)\n    Parallel->>Detect: detectDeletedComponents(Remote, Current, filter)\n    Detect->>Remote: iterate remote stacks\n    alt stack missing in Current\n        Detect->>Schema: processDeletedStack -> mark components deleted (deletion_type:\"stack\")\n    else stack present\n        Detect->>Current: compare component sets\n        Detect->>Schema: processDeletedComponentsInStack -> mark missing components deleted (deletion_type:\"component\")\n        Detect->>Schema: skip abstract components\n    end\n    Detect->>Parallel: return deleted Affected items\n    Parallel->>CLI: append deletions to final affected list\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~45 minutes\n\n## Possibly related PRs\n\n- cloudposse/atmos#1327: Modifies describe-affected execution flow and helpers that overlap with deletion detection integration.  \n- cloudposse/atmos#1535: Changes path-joining and stack config discovery utilities used by the BASE rescan logic.  \n- cloudposse/atmos#2061: Prior updates to describe-affected detection and affected-reason handling that overlap with these additions.\n\n## Suggested reviewers\n\n- osterman\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3</summary>\n\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|     Check name     | Status   | Explanation                                                                                                                                              |\n| :----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|  Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                              |\n|     Title check    | ✅ Passed | The title clearly and specifically describes the main feature being added: deleted component and stack detection in the describe affected functionality. |\n| Docstring Coverage | ✅ Passed | Docstring coverage is 95.83% which is sufficient. The required threshold is 80.00%.                                                                      |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `aknysh/update-describe-affected-9`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=cloudposse/atmos&utm_content=2063)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/cloudposse/atmos/issues/comments/3871846840","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:30:09 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"A01C:32DCCF:1F0D87:82BB3F:698A0B8F","x-ratelimit-limit":"15000","x-ratelimit-remaining":"14766","x-ratelimit-reset":"1770655072","x-ratelimit-resource":"core","x-ratelimit-used":"234","x-xss-protection":"0"},"data":""}}

1 similar comment
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/cloudposse/atmos/issues/comments/3871846840","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds detection of deleted stacks and components to describe-affected by rescanning BASE vs HEAD, marking affected items with new deleted and deletion_type fields; integrates detection into aggregation, updates schema, tests, fixtures, docs, PRD, and bumps dependencies/NOTICE entries.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Core Deletion Detection** <br> `internal/exec/describe_affected_deleted.go`, `internal/exec/describe_affected_components.go`|New detection logic and helpers to generate Deleted Affected entries; new unexported deletion reason/type constants.|\n|**Aggregation Integration** <br> `internal/exec/describe_affected_utils.go`, `internal/exec/describe_affected_utils_parallel.go`|Rescan BASE for stack manifests, source StackConfigFiles from BASE, and append deletions via detectDeletedComponents after parallel processing.|\n|**Schema & Telemetry Mock** <br> `pkg/schema/schema.go`, `pkg/telemetry/mock/mock_posthog_client.go`|Adds `Deleted` (bool) and `DeletionType` (string) to Affected; adds mock GetFeatureFlagResult method.|\n|**Unit Tests** <br> `internal/exec/describe_affected_deleted_test.go`, `internal/exec/describe_affected_test.go`|Extensive unit tests for deletion detection, filtering, abstract-component skipping, and test helper additions.|\n|**Fixtures** <br> `tests/fixtures/scenarios/atmos-describe-affected-deleted-detection/*`|New scenario fixtures (atmos.yaml and stack manifests) modeling deleted components and deleted stacks for tests.|\n|**Docs & PRD** <br> `docs/prd/describe-affected-deleted-detection.md`, `website/docs/cli/.../describe-affected.mdx`, `website/blog/2026-02-08-describe-affected-deleted-detection.mdx`, `website/docs/integrations/github-actions/affected-stacks.mdx`|PRD, CLI docs, blog post and GH Actions guidance describing deletion detection, new output fields, filtering, and CI/CD patterns.|\n|**Config & Errors** <br> `errors/errors.go`, `pkg/config/utils.go`|Adds exported ErrNoStackManifestsFound and wraps no-manifests case in FindAllStackConfigsInPathsForStack with that sentinel.|\n|**Metadata & Dependencies** <br> `go.mod`, `NOTICE`, `website/src/data/roadmap.js`|Go toolchain and dependency bumps, NOTICE license URL updates, and roadmap milestone added for deleted-component detection.|\n\n## Sequence Diagram\n\n```mermaid\nsequenceDiagram\n    participant CLI as describe-affected CLI\n    participant Parallel as Parallel Processor\n    participant Detect as detectDeletedComponents\n    participant Remote as BASE (remoteStacks)\n    participant Current as HEAD (currentStacks)\n    participant Schema as Affected Schema\n\n    CLI->>Parallel: compareStacks(Remote, Current, filter)\n    Parallel->>Parallel: process per-stack diffs (mods)\n    Parallel->>Detect: detectDeletedComponents(Remote, Current, filter)\n    Detect->>Remote: iterate remote stacks\n    alt stack missing in Current\n        Detect->>Schema: processDeletedStack -> mark components deleted (deletion_type:\"stack\")\n    else stack present\n        Detect->>Current: compare component sets\n        Detect->>Schema: processDeletedComponentsInStack -> mark missing components deleted (deletion_type:\"component\")\n        Detect->>Schema: skip abstract components\n    end\n    Detect->>Parallel: return deleted Affected items\n    Parallel->>CLI: append deletions to final affected list\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~45 minutes\n\n## Possibly related PRs\n\n- cloudposse/atmos#1327: Modifies describe-affected execution flow and helpers that overlap with deletion detection integration.  \n- cloudposse/atmos#1535: Changes path-joining and stack config discovery utilities used by the BASE rescan logic.  \n- cloudposse/atmos#2061: Prior updates to describe-affected detection and affected-reason handling that overlap with these additions.\n\n## Suggested reviewers\n\n- osterman\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3</summary>\n\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|     Check name     | Status   | Explanation                                                                                                                                              |\n| :----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|  Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                              |\n|     Title check    | ✅ Passed | The title clearly and specifically describes the main feature being added: deleted component and stack detection in the describe affected functionality. |\n| Docstring Coverage | ✅ Passed | Docstring coverage is 95.83% which is sufficient. The required threshold is 80.00%.                                                                      |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `aknysh/update-describe-affected-9`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=cloudposse/atmos&utm_content=2063)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEYDEZyAAUASpETZWaCrKPR1AGxJcAZiWpcAIK09EpeNPRMzNz45Bi46Bj0iLhoDADWkEo0YvCxkARZ0gwU8AIk6D5+YnSQABS2kGYATAAMAGwAzACURlDBtMjZouL5Pvh8UTFxuMiYyakZQyThtfBYABIAooEAIpASyABCgQDKWwX4kAAG1Mz4y4glZRVoVSN01xoGUAByJAB3fh4bh4ewMWAkZhoSA+eArQZca5hEgRa71AT4fBeTDdRL0ZErVF5DAAfVwsm4JHRdWuU1i7HRExuKTS6Wu3W+/RCc3eNXoFH8iFiyEJq1o6PmNxREQ0rIyXx+kECHiIE3UsGYXCpFHGFGYc3soli9G4aEQyHwUj4J3O9kW6WQgBQCFA+dCQW0XeWZVDMJCIdZEFCbHa7AA0kGhFEyaA8HhQswU0QZ8TmopldDlDuuAG5Xe76TNICQAB5IRPrD1nC4CMEYfAJSvbPYRqM+hLm6VEtEaZUCFJUMRJ6bsZC0tipWjUNAaClUrgqAdpXAc9CC4slhgebBKeg+CgsIrhEmQQUxCjiDBELmQABi8BLXEFYCemGO1ay8EFYgm8j19rZBQMDhIM4S8Md1hSfx6HwN0mAwa1LyDZt9jNXBYEQPFhQApYeEFRB2H4DAPHkStPTXCpaCQJhrUzJUAGEAEkAHp6P2IhsHgKcMAYbwNzQaJwMuI0zSoGh0G4bgSPqesMDADNaDxKUlAHfB5DqBS8QBCZ0h8Dx8ABZBsADK8bjuB4iieUpykqaoIl0MAAEdsEoWRFSgaBpFmLgAA5IGwDB1AKLzkBoyhAyPYl8ieMhnDyOYkmLWhSEYc1pDzZpgxoIgxJPGgUiMkzQIfXBsHXahgoK5i4RLUr8OYmKMDih5mPMxB5OKaySDAN47LoDrxQ6nJRgwZib12fAGEQLhsG4Kd8uElTnnKHq+VlZhaBLeo4QRRAI0Fc0RQjJjWP2UsBKk6RugjcggRU3AD3kbToz0gyjVyfJK16j5aBfB1EA0DaSwjCFMFIfSiGYgQIeLeIXAjKUDzQWhoW4fy5uoCo6hOtjg3UeBqEkCo/XAghyAjXh8By6RpsgHzWgAUk5JUbBIPxBR46QuFsfYKtoSbEGY3haGYpautWvrfoUoaRhJQHaG+AwLEgeiWD9BI2AtNBSGQBwnBcPplRCfCCIFEgJHhIE/DoARAKlJjKoSGrpHqZGhGM+z8oSUsqTEQmxmZb1kA8NkIphQtR3ekbhOMyjuxJclKQqAAiCP4mT5moEY6IDykehKAPPhYHmDww8SqjtfrFJ4Cm+p1gexRsF4+gtgoChfnwU4HQAWUweA/AK298AC+hmOLNuJgBxjEDqPFjO115EuR3cilrIMIaICL/3I71Iz7geEiop4rVczPIFZnxlwmWoZRPSneItQMZoIxgfGvABxVFVfiUtcFvA9mAADVnAz2uhuB6y5aiQg8DqPCk0aYqg8KrZMMxECBEQLsbsdAEaJUFJfH8gpTQHgfhgrBtAu6AX/Fufwgo+D10IlKeCIEyoqC8JFaOc4SDMQOsKDA41JqOHYP7LA9tGL8UEi7Wa81ah1CmKsFWLFcbnQkXtewbxURPWcIFUyKhh4JAgGgPAhA0CSVziQCM791AbGwAIZUH0sDKMuujHKyMSDdDzH6esfAaC1WYlsK8pdECwFhA+aQvZVY9TwLAa+kRi5XgqN+CYu5Fb6GMOAKAZAYJukMQQYgZBlD2SiGweI2o+CCBELkKQMh5BMCUFQVQ6gtA6FSSYDyCBkCoEwDgXJpByBiVqEU9gT40BAj1lGeQcgFB1JUGoTQ2gHKGDSaYAwvwADy0BGL0S2BwAwyc9lK0sIERieS+mY2SI4cZ/A4JxJ1m4SEn4qjo2kYaEOFAUoYEcOUMpbpS68QwC/aGk1MjsFKC7SsayNlbMgJMs8IcGARVLOWCKABVGwAAZZAAINSQFupQA4lAAwMlNNQDCOD6DL0NH4IEt1IC/LIC/EF8IAaQFWf2SgEhWEVFBvEjpPFtxKB2VAZFGMFqFGYNgDw4gnGBDNBCCozQNCtFpTXelN8SBUiSGQBg8hUUYthAA/gHg6kHAABoaAAJoaAAFrKr+QRZAhRcV8AkGay1Nq6X/LCSzdVcKoSRzSAeC0OLBEHmMkUDVSgeJMthMyVZGrPJeAnPDZUAB1U4kBTi7AANKqPfvRKwyqBBUFBaorNNjKDkHyhGKwB4CC1h8GAQUIcIhkv4OhPF6Evy/VEhSYcKZZg3kYnDRu9irk4sBJAbuVg0VgAVUqj1DK4bRrqCQDQ14QaUmLhQaq8AvBoVgC+UQZUSBCHwOsJSiUmBt2kNMKipk0WbK2L8O0uqeAkoBkqAY+N8iwXdDS6AJroDMQfVs34UK8GUC1RUKhlBUiViUBGrV0bGETHwrelF6KnmYw/VAU45tlDxkgqkTmlo3T3DzvwPgUizm2tVZAXVDqrh4K8EOJ1p4iRpXxRQQl/yIzrC3DuCK9CKBNXjPuhK9AF0VB8QkCDHMH43m7usZkgoJhED7gAL2EWO4UbBYYPWXau9dwYCIXhPL+mlCHMlIckZqvgU60X4iw6Kq4iLq6mQIvYzCkAsWdqwO2yAELH1ARoPERWQ77DRIvFwAL3KdYUTwnQFg6xMC4GklJ+jmHqMufY3pEY46AR4qs5qni8hrQ8dUb54JMIqUFdo56/TJb0AhDokYcwhzJUFJJIxgo9ylBbmcMI0jG5zz2WZKCaGNd9P42kIbDu5AjBovWC7OLdAuAAGoACMm3WjMTADt9oRgtjV2hIUxQCTzaW2LFUCYnBJ10HgI4XZ+yfjLP5lNIWFARZixeBLH6A1UT9WGPY+WOy9nJwOcqY5vSCm1DGc4eQv7VuICMAMQ0PMsgCOKR2Q+AtPvfc6r976/IAcRBliDjaRQ4Ol1MtEoEhRgeHzIX21BTmg7Bl63HKyLxbI/R8zpV6AJexwEoljwiSg4TkAdfchgZUOYJHU2jDS8cRQ4obFTn6YCfbzGlxUSm0MoQARoNj1tvBpD+uHIKSE/yib2GxHgE8/5GcRUxOhdhAyWAjlTE5hSOFHS9kYo2YdtAm4uxpXo0ETt4RGrHApCMt9YiJypBe+gNLif2R4ar5X4p49kKzGyMBsZYhBiq852osY1SlHQswew6RURytUbHMADBOONWaqo0Rp0sokBcdHNCNARPMpF9YGw+w9E07BRI7H2nuDF3tfUK9cdhokgjE8SE0Iy+qPe6or2mEIx0BSi3+1q+j1V5qSKLiXWjr2CbiQxgVfwpoFNw2dgBN4w+DwMe2GcTeLY+ZYH4MATFScRJxCPPAVRHGfYZ6XSfSIERxcCVtOTKDSrbFH2X5IKWfNKZAKha+DXexePMXeIbTbLaQVtL2QMYXPrQgjsDwbCRAX2fuaNOnYSMCAfdjBwSVZAC2GECAZyVyGNPgX3Q4SMRQRgj3FBf1RKSmC2YA7IbQLwegWOVKefHAiQ+IMALwKQeMBPDAVfB0dhFfBRLvehXvQwqUPglwQMCmbcQ0AcJuOqWocgnRRKA/bqI/PXEOPhNrSHFUAfIbYSALfrV5fw39H2W7WocbGxX5abcQWbJUebEgdrSdfeLyO8XdCoQIUTWQDTSgRbZbUKG5NbSAdbAAFlaF2zAFaCOxOxo1qQuwtgnTZj1Duw2HgCIFgGewh1ezACMDVEBkUDB32WViOROVh3OX1kR2uTBjiKgCOEcG4GQHfiuAIGxFBkrHK0dwNTVEgE2w0GaAAFY9jhJtjdiDiNBDilRhVnl3RXkUoCIEhf17gQ82FitI14UXZHVAQ8U0IIRmJPFmQNis8jMNBWx1gvwHtVFQZ9Qi00huxmISxWobd98qICAKAmE2jm9IQMhKBQSJwk4IxSBZgQVZACS0ASxiB8AIwB8qA9RmBm9YgQIwBIJfZcACTCBL469EBOgIxZBHIIx8ANUwAYhflZAepelcBmIBSn92Mj42SjU2x+SclYBmgCSyBKYCAIx0gfJVEX94w05ZhW0Pk2BQ1LR21uNORIB4iQ1h5eUqJvwmdENSt2MLYKt0ASgHhdcChBRzFAD+UIoaBE1URk0txh4iErRL9uMIw58EAr00ZS5+wKZa1BBsAfAO9EoOVSgbT/JxBS5e1ZV0gF4cMM18MqB4xASsBaxog5hOtvEqAbdxApBhxCY1Bcz1JgSIwOUJUOxuB4BWookOzDFJVWoez99cAGANBC8l5g1mAvkx0niJU9d30nN/jnUCUTwHAqhQk5hypaB3YoJyUGAr070iASIbxVlrRYx4wmiRguB6wpkuVCjEA8xYhpIJxkZpxRZ1VrMnSXFZ9N8nMYQliuMeNoV5iEY1oXdOIjUwBxA9NXibMJNgw7T8sIF6zbdBRnJwS/9FYkjfCr9/kAi+tRBgiRphswiLwIi+AJtojX9YiUd4iGQ8DZQYBIRyp1w7zkdhIAwiAmoHDVFyKDTKMeAoia5pIgjnBahaLo1Kw6i8xAj+43QdQ4MCLCg+injw1vztUnNyz/yXzZBFYlspdGBCjaANsdtOg9sABOHyao2C2o87Z0q7Jo27LgbuB7J7cHPoZZYTUTZiUsUQT87ncoUkdPOgUkfUgGNUQYiHYY6HfJfpcYy5JHR8w2AYWoSzFXOSJtey/5YjbyAwSAXQXnfkVmQ6DATBcUACtaOgUq3hCqwHchfQuoSCS/TnDcJFHRaqs2Mq6FfSDIXoQqqAHQ6AJOZBL3DscuTKkaqkChDIV2Q0DK48fIThXqoFXoP4K4TiwoASugIWEShgGI+Qbi3i49J8ureCVkb3CS/ycgEsUbVrXCms/wwoQI4iwbUisdHamCKi/amIplObVzO68I764SybA68S3KVXQrdcJ4sQhWPIoy1bUy4onyPbKogwY7Oys7JQRyxom7aLe7KiDyl7CAHogwHy2MPyksAKn7YK0K2gUkBSNdfAaKnwuK05eyeHFwMdZHVHHkP9CdICsCCoCmjwKmmmwnOmrqxmvPbY+AKfV/UyTJGCwgTJJik8RGdVW7CKX9X3fCYeNEl2SZKYOKUyciOoQUe4GgWax0PEQoFCBfOXdgG2zCcJXAwXQVJi+qiIMa/tDpPwhaHef6eoUvAUkaWMP3EJGssBRnZAV/Z8XeHQy0KiygektQpnJagiyZFEdTJCYSe+Gmb2ugG2oSgui0Iu2gX21BIdG2hGQ8xwCVQmUyQILqxrJlG8Mu0hcUEutsas+MWSHqfsCBIcCKjnGEX3XeTsCunzbFHQpPFOb0ZODu4hBBOMKu0cdBaeuoIJCS+gaBHUPEdQWHZATyNuN4CYZgCMDYFYZgYW1tKwNkPFCK1fdIeASSMOIewcBIZ+pzEofwBaFuyWNul2bg+/f+kgCuwBn6QPKEZe+Bcushde1MGu/QuJWgISHtN/AwqG63d0XeNzCsEMPYPMfuSAB2uFR0FnUcKkg6RMTsD/OMP6QCHQgQqh1MZ8s0rFF+E2/CHgVOlan+xAV+9+nRT+5cIiUg5c5wV+0yP0R+UyUezsJOmet3Oela1OT3ftJepUJAQIMRsQJBpnYaUKTR1nUvN8+aGcFagAXmscgGTkXGHtwGTi4uEc52YBvAUhgeYAfqoANHtAoHsN/toYgbISgf5G8cYBBVjHgByLAe01/XCfsiPoNAjFrF3WPJVlMfYAfrdylBttOG3CIFbXWAkHwBkaDBiFBGbVCfFG8bcsnGnA7oFMbpoArvqdRHfNSCKDqK4JASyiuHDliBkw0PgDrwCfsK/zqF+AEhvVhIjE8ianiAjH8QtgPAwBNwzVSFIBTwjH/FPppIvrYcEoMyIFIG4x4BaZqfaeNyHWykhv+WaeqcxhuahDuZ7weewN3VoIzVlRWH7lwBLqlECDS1SyQBrXwAqQSFAbmIydOD+dLh8EBYdBmbYH/hYEMe/hAkgDHlhaNRBc8PEEQAhahdRZIHReYExYZLaIJMHDZglWkjQZpyDALknhvDxcruyfiFyeCXnhSgZ3CkbMMZ5bzAKaKaKFKAo33EPEnsvS5YSCajYA7soB8A0GgEHB9FysCen2jmcGHkSmhFPT4A/x4g+v/B1FpMwF4jgTAgoKVA2BLhW3lYKCTi4IJnavcyDAuryuwOZAOfPv1CvpvrvusEfooEQJvRGDmH0ajxrLtYMCsH2qpvuvzniHUBqUfK4ASMVmGKeo+peqIoG0+c+qBoopBuoqmykpmMCwZCSN7kCgPjSLYUyNjGyNyLa2VmgG1gRpWxMo206E232LRs6K8rJtFvFoYECuWhIBCuloUnJC8mZtZtitGISpvwmJ5pSoMDRwLE9yt3pVtyAq9ijpFp/hE0pv8sndppnfpplvFAXZSGZpC20G0SDHFUlTfrYQCiCl31YdeuGgrsMewIChBxYukxCgUGtE9tOEDDYX1OwawCqy+kjotqhBfwOFCidviD90xWxXHuZ31LPn8XEHXETsyvqHfalTg/leWEqoBFwYC0TqQBMSpBATPj0aXBHudbCFSG3IqCEbfqpHoDqDvLPFu1Ycca/uOddqVBLtYLxXKGLgtmZFQ4HBrgzqihUsGfsAYJ2gWAL3GkyrmHdKDUo8/a5Wdc4THH9dpKDY8FvvSOrTDbPgdqU4ig4po6jhPGz00+DHZkIXQFsIdA0Pw20PI9LxhEtpfYikI5vA7gQ8xVwfIilAduusvzTZbw8BvFVmvSHBhweZ0wdFJEQHFfo7IGOZxVmZMaIMrBK/NEhCLOvpgTxV0ZjcMehRIDc4BPdc8hSGng46cfa9LwzLyDDXg882jh3qpA/QMGH1/aIzBcxnQFwHuEQCxZpaAjsKHEtpfxdt/qw+RbZDTD3m4AAG01OrwABdTAEk4MMp8ZxnQDzziLrAMOkkCO3eeT8NgCi0WDIiSAae/CLsr53aG/CEQLrJ9OiMWuyH8a6an0pJ7BAHqa/E5HnPZULqxBVtMV7Aa8I2FE97uMW7mEUSWZgfWJxw1IjlUua41rzj3AdriGKbAND0h5dmQicb2WEUHCnwvN7rQiuOItkIt0L60u36qt+ija8gXseL466gU6ktlNvasGv6l2aG14FrEG2GvTgy/I4y6Y5G9bToAAdgqPRsxvlvspxsFAaLgPxpaLaI6M8u6KMHHcvana6lnclgfc0CipHZXfy5oy5smP155VSs18dkgH3soC4HuNmkwSCpIER9oArswWX1iF64SEKDN1EmgxKi/zag6kT7+xJ2lmd3yAi8gE3ikBEVbvZ2QoIX0s/Qj93x2UGpgC8gT+neT6e/TrT65/8yuGtH7nkGUabFDHY2bVt0KE9ARl+7M1kdiHUHVAUe4/I4qli2dc0JWCc0phD1HTI8zrmCz/uV3m348AjFLzkPSPJXn4+vyArojG9pJHh9bWT5CV2m+Hb8z6766h78Qflb3g42pkQoMPx8B/hd05PUyLrQI6edJk3offP8jKgRRlG11UuOrEcLLFT+uneEPpwyCDpg8oeegMeyZ4HUBWw0X+vqw05nZ06iFIOB2XCjgCdOogRggdVHp1B7ggUVElYQODcBJ2JAR0NwkGAc49+9hEkEpBhrSM1UdHbFFentIIcXW03VtPSgL4xtpOCWesLJi1plsIeTNJUFsDurzBKeKQSDsoBShO5yObeTMryksjTtiqLaX0oJg8zBcvutQRTmgGU58BlInTG/rSipibxoBboIHpwRzYdYA6/PAtoLxIr89QipbMbD9RV4S9DYt4EDrq015Ig4+3AX/i8H/7ih++9iTPnUASAAAqJwteGgDgVJYLtXYF+ACaBg8QdQNqOtyDBr4oQM4EFqt2aEsIRo+0LWjyzqFXhug6ISsNcDd7U0r2ktG9tLS9jM1rgSoFIaaw1rpCbgJrA6j/0mG5CGqhjfISNCKGQBShXkCgtACGEc5RhZ7Xyu72vZe8foPvWYfMNSFLDdwSIVYR3xSDZDygmwn2oAMgHhQrwewg4Z6zVYnCRhYwiWon2uH8hbhaoOYW1jJqGVe2BvMyiUUsrDtnepNV3ucIvbjCPeLwCEREFJAO5aCS7f3ocnZpjF12SVKYmH29RSRYSRCS7FmUy6y4p+P6IISsEJiNld46JYqGwnEwqNqsVYc4C+BbwYBX2EkSmGkFgAy83oCdEUW1XNo7caAeIBvqiT/CBx9C3Ik9oVCEx8odwu1UsEAVqD94K0PWRnAl22jpEbB5EWsAq3VwoQ8QYkVir1i6R1JJAW8A1A7XEwECG4+/dKhOngpRouYr8IMHUE3joQbEGgKIMxBDI7gYgv3VqCtxajcB0gkMbkSnn8j1AwxsACMVGJjG0A4xBEBMatyFgpjmIhI12vRhfhI434Gge8EkEQQ21mhiAIdDy0QBDwKAQLRKNgA0AAApM9BgFbHCQpgeAC7FbX44ajqWPIxcuhCLJXEaMrLIuCXCfhwIzQudCoAPXrBgBoQDbCDguLTIwQsArcduJ3B7gpFB4+rSTFTHdBKA14kYGmAvF34r1agL3YsNEF7SBInYKmNDuJC5GTitRN4OcfZA6EPAuhBXc0MdWxxcBGxk4oAdIA4724aAg4+sKMgNrNx9Uh4ALMEMTC/oAsnoMALbFNjggukqHMcdBOAhtFYJaCfsAhJICtjD6uVaCDzViCIQIoZuZTsZGkjDiM87IhstOIwg3hWY5GWoF4HUxaVSBzo7+sxNgy1AUI+EtKGbCn6ciJx5EqcW+hnHCRFRrwaiduHEhejDY2cUbM1j3IrdRwC4CPvLVGy+s+Ae4kGJONbTljQhyoPnqrkiE9NohquWISmzF6JC02dFfScmAvDNYnhNwAuMihzLIBk4WYnMSwGjH6RYxHpLhG1D8oTxuMycOYVnACkdhlhdIN+PYyikCBIxMUvMQWMSmJjBYyY1MZOLSlKgDJ4nZeEUWuDYA8pGoaKcwFimhkSpRYpMaWPLHVTIc9bfuKkVgnKgsiORCgB2zMA9sCiiI4op0GaB7ZNsJREdi73JqYixalwyYXiLCrljSQpPOMCsGJGeUA+8VIPhcgRybtpikvDHmwT2leAxMK9eRl62xAsZEwOoJhnNSwk74ZcDlZCUxRMa0CJJHrIPIKK2DcJvxFQG0WrmBkoRoxB3A4O60e4ADaBraFjpkl1wvxfco9VySfFLLxh6ayqR9pAEYhuhEZ4oIDuxjqgEUukC4qkvclWHRxBQlM6XBVAXGUFOk/NGEItU07k5JuNANGK5IIZhwzmgoXOo7lgL8i9E6AYAZU1Tq7xO6EUUgTz1zbhCXJWAqIe9RiEi84hlFUGjRV8n/UGKofeLNtW1kiwK24NN6p8116I0+2xRTbPNMqK2VLe2Neok5Xt6uV3KzAZaeiIMAVSGocqaEP7PXwzg/eR00kau1Okbtkql08PivFwDaQ6s5sj/jHgF4Y8gGW3YGX7NaGBzs5IclmgVSKrT1MQ2IfkZAFkACQxaQgXhH8RMQZyv82zMcMlmNzcAKQA1QuSjypADCS82KcucwErnVzUYdc9cA3PqBNyoQLc2QOtTA4vxl436Air/DVoBZBApmDlAbiyDThUobcXAdCnkDJ9EBrCHUVRBbzRwYBmdI3GGilCcJrZCI+JIbwdnm8aiLs3Gnb2aIeyiaXstEcsj9kBk/UD0WQH8SBQAKMgu0h4OhCpjhVS47AQ6UMXDmB9OaZ07mtHOpHcgV4nMidPcDmoThok9AT+H/H/rHpbwIcIgKzA4K4BGhbyJVHGLAXXhbw+CwUIQu1gP1ZA+kZGA0OKFULokNCuheSyIUkKuy++FKXbSuDdwgU9ESBcs0cGZN1AyARmWVCwDU8XI4CL+nLGb6oKFA16egiaAiiJIvseKLBYoEgC4LaF8vehbwukBdlyFRAJVDdzxDFC1QGC9IBoHoiXlhIIijIGIvhDxA3F6QVmEeQ7RXAHAkkcTj7BGDaZMhrDIxdwoYXELzFkqJWWEPwo9ZXqQve/lrK8mREfJ4gPyUqAabYKgpDUyJSYp4Xaw+FkqSxZQtAWcLaxUSohUwpYWKR6g7CypVTGqVFLolpS1kuPELjAj/MScG4N4o8WMgOcwtG4N/KJBJp/5DioBekBAUpBOFECzxb73wDpT7sYC5IG0ROrrgSCwnHRXUm6BIhClDhdpbErIXOArFiQSefsPsVAonFl5YYb0s7nXABl4i3AN4t8VJJKA9yk9qMtLE/yJl0y6ZbMuoULKoF0IqaUbKKJbYh2jsjGo/I9zW9LseNV+YTUewfySayyXfDulqinV/ZsUawV1PajXsS+ZOMvoDnsQEqNAvcjwMu1gUnT4FUcqkbcm3Ycy6sx7GqA4WW6rdKVFc1hkSvppgAqspOIHGSpGiUELOKk7oSeAlx68YQBEviQjA75n1aSFXK/j6jUjY5+ALc7rAqvZwTcTwpeOVWpNgB8ZdRu4KmoaOJQziUZlXPTM3JqYB4aC2EbkQrw3g8C7VS3MgAEP46ogkIEEU1RFHoKlAgwUoexbSPEil5YKJASWcpGnDCgyoD8ScsQMoCeIPuPqwMGOA876Rvu0ILaFiloDoQLScAVAOyq/yoB6EmqYgUP0YGj8RV5mEmbAIBneDKq7OTsPjNVXigYsgTVdN4WVmJLU5ENYXiNmBreS9ZWSg2RtSHVltle0RAdR9W164DwVSNDbMiOHawqsa8K12UipcooriaXRH2ZipLX1QrB8UAlUX2nbErhVg0cvqNCDgCqNQQq36PqU/JSQ1In2EdKKqpU0qocEc+lZSIhX0Ud2aCoEMBOQDbjBpJg81IEG7iOYRlogkHFSvsDy1WmKA8jr+mplptSODoXsJgklwgN+mpeMgGs1iAaqpQrIUgNatHqAo5q/4akgGxrwRrYA3pdQXUAkB8D98jofaIMAtJbBJRFXfjPyhdgWNpwXAfUlwAcVOZCNX4YjewBfA4CDqGZIfPcnLVxzUiISv2B9WuroQN+9yeOuOMAioALqEZaQQ1Uv54cuqXAZOEzUXq54O1XpFyK2jUZJwLNi9CTnGGk7xKnJKsrTm1VnWazJ18Q3WZW31nVsEidbM8QkGGktsSIY0xdbbKN4oiYVFvU7BuufnXZkVbld+d7IxUhQsVfFXFU1HxWF8+VXVB9TzJJANR/od69CKVqfUIZ9I/8sjRQU/Ukjv1cCuHAgpD681VFC1CdCBr3g7iTBIyxrVeG5V9z2MZuAiGmxAH3Ig6S3coHqFeAKDbAJqoAjF086saGA7G1RJwOX6lBTIK6MsAVA5zWiwQvucfnsETV/pYgQpXOEgBJDl41B8HOVVuKX7cCRtYHb5e9kETe41N9kYrUAzAKfivB7uSIM6w4GvaV+RAfZfYNqCWayEycGzQ1U7X2aEO89CzfqSXp9h6e0KNKC9q4GQ6UAyACbYREhmaDxtw6pRnnm8L9BnJ3m5Je5IIqeTh1GS0dTNiumhaDA8I6abfOXXtBV1SWq3pupfnbq0UBkLLWTQPX58j1fydvKev+3/ZSV6fG9f9GfX1aKt2sJrRXK/UjE2tiVc6UgqZV3MDwvonrcBrKn9bwNsbaDMyEY7bMEUCEKTRsygUfawNjbaVUZUk3rMSNiUMjRUBG6cp9xkil2DCFo3Kr4OEahOYLI8w2J2BG2iTbbUBlRdKwIHEyh13jkkByuqXRKJ6AdVSzsIX2v/IDICw7a3tT09OlH07DlByuuwLYGii2DQAtg+wSsJ2mQDLaoZ/pYuI2G9iHbkmWAE7QkABCdgduFGc7bsGlEdcuupZPwZvDYGPkEs9cY3UQLkp0z0isMXpkBGYQFdLGlA1gJHFpod644mdDzXhWLauTfNHktJczoSGs7slUAMLQNoi2r6otbbcaZzr15LriizQVGolrhWg6EVtvNLduoy2orxdRgQrP2CPpQwIYzENoM0HaCVFmglRHyGevFj8rFdA/eWI+Ba0666V7Whlf+qMD/AgQgKSGAXqETRwRl++0yNstsGoHW67gzwYtBFUJdsN1BZmQkD62/SLWF9WwsaCkLgT+A1oAoGctRBySX47OQoOl3EBMDMZnnOoMTuw5kQPwpO9XKPv5HN7T+szP3OmInrB1t6wdBQ8DP71QyOc9ogPIQIfh1ZAdyc4QRYKP6r45Nl5GtZVTqDFycQGAHQ5lXnr1ANG6dFxsyGTiL0wEUkMNDSjh3igXGUocIw1XzwZBIjrdTPI82sC3bgCX3CKBxC4hWs/d7rXgi5EQV8AhAjkLiuqneqH6Gq6EmvPOvELjV/8pql2JAW7ymF8g8BF2EEgMgRRmChQegrmXFHSRvBqkJ6ALlgIoE3cLeB3LEHOmaDg9LhZKFyiwK9gtgsx5Qk61ojI1JO4jRRuxXVxicdBlO8UHmA5hVdxRNCCHvhzPkhHTdxzXsBfEgwkYNJPEm+ALCcx8tT2eEZcDXAjo9kqQE+PjkHvhq88vNSSwtgzrIqmyR1QWsdSFs2pz6BWKSvzaLxZ0Qm2d9+y3U2wyKjT22XOiFYb02ydAEtVRT+WTXAMBgaAosPHFuF7JFIdcOI8oDSe6j01MD2uskWu2D4XTkF+PZADSiTk7QU5Z+yYRepgggg8AXAX3K4axDuHPDmdbw7ImdYAAfbQ8cecAc5/A4PfGfB3KQjAbwBg0LMIICyrIhTCQXORJpLAXReRaAZhfgGRg9Z+NeokHT7i8OcIVtfpDzDLusGsN1gVEGQtgAjrwdUBiUejtiG6iH9NORZI3SOmD11YyDRBSbgP0gCAAcAh2ERRp65M/8AnwehiD8gKaIYwZEQCABcAipzyEOjb0WQ7QPV24RrqjOJHp0auBfd3Gpc3I65GYiFHW0DR6AoLhAJCQLBGclRSgrjommVERQTgUuDzr3RAmo6Ns8MfqCh6jmo5tSF6TaLnNvMjCV5GIWQDMESzNR7vFJwi7S1LyueR0oJVI3Bdz+LB7rVX04jcRrWeq1XFKEg3QbmIPY04Ksl+AdnWjdOFDZVSbWadvDLxt0oGj6aZkw0PaYbIEQFhOmnBb7LsuZ1yy3HLDhQas/ObOZFYvIY56OJWAaNfH/mUuY/bTqBPqzi2TOnQYiYOpJDVFRo36jyd1NqyWUBp8EMHN5X8n8ZgO6aAXKgD3gEQ+S5GmKAao0g3D/gDw8qd41qnnWGpsQF/yKrsWjUnFpEI5qpA0gLuRAPMAoqDG+HxqLjeU4EYdAZxBLqp1uuqeECamyLqeCdEnKjOpBJuNia8xgDb5FU8Mo6eqcjQTO1rTIyZzzqmZQsZmsAWZl6MMfzOl4Xj++fs5dED2tnszd0HwUSJRONtItGJ1/ViY/1bYfI0KzbKAYMDEnID2+ZiCYU+bMR8pPULzK1BK1BxGT2B5k5HL/VdbANdWZOK5fL2JnYgLjKy/2uoLCJc8QVDvdpq5x2DhLTgJeLQSuCx1zRMpgGeqKO54hjanuU2l6zhnCFUgbyVENCjrIN5zDPo0PCDxTkKRkdi8UIA6b6XDXxqQlb0EIr3jRgWDyR8MsAUApWIbEdiD6hObeiIBAokkBa1KGYvFHSe4kKo/QGEIbm/a/kIqJAEfPPm4EJCCKHUEKNgJS8BED668Ekh9HJqAxyAKelsSnZSglhlDBovQzOD1UtRw0YaEH0iYOrTObs/kAwqcReG24703jNMRWhYw4+uov+vn0WG6Ay+stYaDMvaYyAP+P1Nh3HxglptEMzrh4LyBeCuxiAB8XYZDPXzudpAQ3u0E2yoj0VRJkgBAdJOIA0SosD8kjBRgmINAVcpkz+rwMVWt2UABoxC2phBoaN9ybW6jEAI8Jag0rGvMb32LCR6YN4NKuSjqwkwvIjFEeHikgIWbp6vp2tQHEEIoW5z91wyC423oIBnrDS1Vdzi1X5BNaNTegEJtSAIxS4PFCKARp70RRvbKQRikPO7WwjPNfavk3CYv3+adZSc0i/Fy2pXAk5cvPir2BtsmJmh7GaEJBDaqi9vWqWZ8mygoAUYHsdDdcNvtnn5srgotCZmIAV4cDLRZMK6KeBJQdo4kyoKwCxGbtf551x87rNLexMbYHZKVwk0YD3HJTC4kVfOWHNa24G9diCxldWw9sC04CYJhcUaCm078jxHcG2gNIPhtiLxHOALHuLfQZAF4K2nhAfqNAPE3Q3oaMc62yr2Q9x9NmE5tWGYHh384s5kFHpZYpSK9SQZltPpris3dYFk6SGEXnxAaulAJWMIooY3Ex7xKUZOHeV3iu6IO4wEeNo1Ltf2TxbIX+yFCHgjxpLNwbhz/fC3/2R46IQAEmEIUlKQDCIN1AmHAS/Qqw6O3sOkgGcL5dcDPtIOwVb+m2TNK2z87f995VLc5QJrAHd1o7IwH7O5Fljwp0CmKrSo5pG39dD9+ihFjrG0AGxDoJsS2PfTtiYeZXLAHeVOwN4Esajg8v+alliZqAA+XjD3dweyKRMBwGhw+UukVH3QtIysJa1wD2RNY4t/lkxlRByLIHb91tT5ioBx3IAIj08Q/vEdi3IHDMIENaAKksUDNUki8J6Tfv1xtOAISp0JypJJx84uD+jqvuJ1D3IHv4n+LVEztQCcHhcPB+gwDVtCMuuHMBWCDixrbh0GDt6MyHpnrkNlRSnC4Cf7WWzB1CJ6/Uidv01sFsejm+bLbMoLSnZyWv/ULsAPmPPZWWxZK0lhhZJukhAXXUmEgnL3RkHWnefeXqSzImkCyAwD86KTqBSQXERAKSBt6WwwqrIQKaklhfpJoUxvY3iQGaD4v2g5QHyCUWN4MBaAqgZoCQE6AdAKXPkToD5B8CEvOgaAfYq0AYCdASiSVzbDC7hd+BVADAOA/sX2JKBB2VQU3mzAEA+R2gDLtAG0H2JdABAzQSyhy/KCdA3QLSHFyURUAt5WgPgDl5tnaBoBOg+xToAOx8jKuBAJRAl5ZRID7FyXxvdoDa58AMB2gPgU3kqi1cQBIAJRAQD4EWmcvkY+xEooq41ccuGAm2Y3ptjZeWU2XJASym0GN4au0gA7doMa5hfYufX8L3AIi8GAovEVhWBmmrW9dQAzcpIY0qQHCpYlHQxXOa/ojACLIAA3gXOTjgsbARwPqnXk5a77uWoCugMnF8CxgCIYYVt20YlS0BO3QKWwIO9hDDvzErbpAOeQLhcRI0s7y+LQQXeFVLNXEGwAFAmgMAu4e2ogGtxrezv0zW7+xlRFoB7uMA7gNLCQHohnutro77d9e9vfZCk7GAJ96IHSDrv53r7+xjTm7fTwHA0gI97O72SAfk4IcFID+4yAdLEAs707gXMKotvCqGH+xnKgyBktIPn76OPB7/eAfMPml+Xkh5feoeMPycNApgGESQfCPteQTrUFNvnYbAMydQIAEwCNc47xC5aEKR501ALFANwKwEdlH7d08RICQeCbr7UT5h+3fqgAhsYQj7h4s0/Yv3EOTDwAF9iPkAdD3J9Tg1uVP9je93BzPc6ft3rIUqOR7s2XuSPNH3iiSEg9zdPAXKHEBQHhvJBHDRPWgy8E9Jd2sAfgIpR1zDjLDfrRYI88wxDtYANDXVrqDDr3APCJjrZDQLJ/08SepPWiQMKl5I+JIJVgof95u/M/2MFPKWJBIZ9maQeslXgDTxh+0+Ue9PJH7D+kCM81WBYBmUyKrAvKkBsvVHyz8ZHPddqiv1Hu6p4To+B22vx70wVQBSioBLKhxBlwzB8wxlgkqADcnCHeJhYPtZN8EsQMY3SBokUl1AG7fKIMwUvQ39LxZuk9ZehvJX0TMp4q+qeJv6amr4VU08FzLu0H2D7gB5iE51PFmzoOUFUCyuhXeJnyAwGREMA5vtAUNyUWaBoBjXurm13AffLNBNstsfYmgD9etBjeKgPwIm5ICBuY3kP2gK0E2w+RUvMH80N95sAmfJPFm9oCQGN4+QVArQEn20BIAlFaADANV6j4YB4vWgAgbbPsR8iUuzXCbsnx64z1oAGXc3p1wm9ddKASi9skgD5GaDWvWgllCn9vna9EBOvZgkgO83PYeAKENAWdw1/sagiJh4I29kzTVBm+xP9jAgKkA8ALCvMs7nyEN/2cigU0GoA9wpes82UtPOntt2tInZ0mtpDNHabdIOl2+uA5v7d079jCu/SKs7zbJ78S//Iff6EP3zr+s8pWg/lHkP3E6xFgjp2Efu9g1ShH4B7fcnx3w2CT8Z/rPlldP4sO9+++nvV4Jv5R7q8kfLf4f29g5Nj+6eHfycRPy78b+p+W/XmLP7ABz/HvrPVRAv739D8bTrf0wxdkP/j91/nfyf7rLO5KJT/SKM/uf8964BLSl/VHmx5OLse7pL7Nf/T2P938ihJ/I/r35n/b9TRc/qf7vwXLe9ves3ZboKAVulAFW5NeyLiW6NuAAf867ShiARB1umMPAGYukAQYBNulPikAP0scF464ArMLbx0AyCOrCqwAUM4wcArQP/4/OOSPgAwBscPAE0ApIBAF6AQAA -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/cloudposse/atmos/issues/comments/3871846840","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:30:09 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"A01C:32DCCF:1F0D87:82BB3F:698A0B8F","x-ratelimit-limit":"15000","x-ratelimit-remaining":"14766","x-ratelimit-reset":"1770655072","x-ratelimit-resource":"core","x-ratelimit-used":"234","x-xss-protection":"0"},"data":""}}

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@website/docs/cli/commands/describe/describe-affected.mdx`:
- Around line 1181-1192: The destroy job as written will attempt to run atmos
terraform destroy after actions/checkout@v4 checks out the PR HEAD, but deleted
component files won't exist there causing atmos terraform destroy (invoked with
matrix.component and matrix.stack) to fail because it cannot find the component
config/state; update the workflow/docs to either (a) checkout the BASE/target
branch instead of HEAD before the destroy step, or (b) checkout both branches
and pass --repo-path pointing at the BASE checkout to atmos terraform destroy,
and add a clear callout next to the destroy job describing this caveat and
recommended approaches.
🧹 Nitpick comments (1)
internal/exec/describe_affected_deleted_test.go (1)

14-328: Consider adding error-path and ComponentPath assertion coverage.

Two gaps worth considering for a follow-up:

  1. No error-path tests: All tests assert require.NoError. There's no test feeding malformed stack data (e.g., components key that isn't a map[string]any) to verify graceful error handling or safe fallback.
  2. ComponentPath not asserted: None of the tests check deleted[i].ComponentPath. For deleted components (sourced from BASE), this field may intentionally be empty, but it would be good to assert that explicitly so future refactors don't silently regress.

Neither blocks this PR — just worth a quick follow-up.

- Add error-path tests for malformed stack data (graceful handling)
- Add ComponentPath assertion test with Windows-compatible paths
- Fix destroy job in CI/CD examples to checkout BASE branch
  (deleted component config only exists in BASE, not HEAD)
- Add explanation in docs about BASE branch requirement
- Update CLAUDE.md with Windows test compatibility guidelines

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 9, 2026
osterman
osterman previously approved these changes Feb 9, 2026
@aknysh aknysh changed the title feat: Add deleted component and stack detection to describe affected Detect deleted components in affected stacks Feb 9, 2026
- Add deleted and deletion_type fields to affected extraction
- Add tests for deleted component handling in list affected
- Update list-affected docs with deleted fields and examples
- Update blog post with list affected section
- Update PRD with list affected integration
- Update roadmap milestone label

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@aknysh aknysh dismissed stale reviews from osterman and coderabbitai[bot] via 43d241b February 10, 2026 00:13
@aknysh aknysh merged commit 2842108 into main Feb 10, 2026
61 checks passed
@aknysh aknysh deleted the aknysh/update-describe-affected-9 branch February 10, 2026 00:43
@github-actions
Copy link
Copy Markdown

These changes were released in v1.206.0-rc.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor New features that do not break anything size/xl Extra large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants