Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixed

- The caveat summary in markdown output and PR comments names the kinds
of assumption the estimate actually has ("an assumed instance count",
"a price from another region", …). It always listed the same three
examples, even when none of them applied.

## [0.3.17] - 2026-09-29

### Added
Expand Down
33 changes: 33 additions & 0 deletions internal/render/caveat_kinds_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package render

import (
"testing"

"github.com/c3xdev/c3x/internal/domain"
)

// The summary names the caveats this estimate has, in order of first
// appearance, not a fixed list of examples.
func TestCaveatKindsNamesWhatIsPresent(t *testing.T) {
c := func(code string) domain.LabeledCaveat {
return domain.LabeledCaveat{Caveat: domain.Caveat{Code: code}}
}
cs := []domain.LabeledCaveat{
c(domain.CaveatAssumedCount), c(domain.CaveatAssumedCount),
c(domain.CaveatRegionFallback), c(domain.CaveatAssumedCount),
c("some_future_code"),
}
got := caveatKinds(cs)
want := "an assumed instance count, a price from another region, some_future_code"
if got != want {
t.Errorf("caveatKinds = %q, want %q", got, want)
}
for _, code := range []string{
domain.CaveatRegionFallback, domain.CaveatNoPrice, domain.CaveatUsageMissing,
domain.CaveatUnresolved, domain.CaveatAssumedCount, domain.CaveatStub, domain.CaveatStalePrice,
} {
if _, ok := caveatPhrases[code]; !ok {
t.Errorf("no plain-words phrase for caveat code %q", code)
}
}
}
33 changes: 32 additions & 1 deletion internal/render/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,37 @@ func escapeMD(s string) string {
// layout, PR comments included: one visible line saying the total rests
// on assumptions, and the list behind a <details> so a long one doesn't
// flood the thread. Empty when there is nothing to qualify.
// caveatPhrases names each caveat code in plain words for the summary line.
var caveatPhrases = map[string]string{
domain.CaveatRegionFallback: "a price from another region",
domain.CaveatNoPrice: "a price that could not be found",
domain.CaveatUsageMissing: "usage not provided",
domain.CaveatUnresolved: "an attribute that could not be evaluated",
domain.CaveatAssumedCount: "an assumed instance count",
domain.CaveatStub: "an offline placeholder price",
domain.CaveatStalePrice: "a cached price past its freshness window",
}

// caveatKinds lists the kinds of caveat present, in order of first
// appearance, so the summary names what this estimate actually assumed
// rather than a fixed set of examples.
func caveatKinds(cs []domain.LabeledCaveat) string {
seen := map[string]bool{}
var kinds []string
for _, c := range cs {
if seen[c.Code] {
continue
}
seen[c.Code] = true
if p, ok := caveatPhrases[c.Code]; ok {
kinds = append(kinds, p)
} else {
kinds = append(kinds, c.Code)
}
}
return strings.Join(kinds, ", ")
}

func caveatsMarkdown(cs []domain.LabeledCaveat) string {
if len(cs) == 0 {
return ""
Expand All @@ -247,7 +278,7 @@ func caveatsMarkdown(cs []domain.LabeledCaveat) string {
if len(cs) == 1 {
noun = "caveat"
}
fmt.Fprintf(&b, "\n> ⚠️ **%d %s:** parts of this estimate rest on assumptions (a price from another region, usage not provided, an attribute that could not be evaluated), so it may misstate the real cost.\n\n", len(cs), noun)
fmt.Fprintf(&b, "\n> ⚠️ **%d %s:** parts of this estimate rest on assumptions (%s), so it may misstate the real cost.\n\n", len(cs), noun, caveatKinds(cs))
b.WriteString("<details><summary>Caveats</summary>\n\n| Resource | Line | Caveat |\n|---|---|---|\n")
for _, c := range cs {
line := c.Line
Expand Down
2 changes: 1 addition & 1 deletion testdata/golden/eks-cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@

**Project total: $0/mo**

> ⚠️ **20 caveats:** parts of this estimate rest on assumptions (a price from another region, usage not provided, an attribute that could not be evaluated), so it may misstate the real cost.
> ⚠️ **20 caveats:** parts of this estimate rest on assumptions (an offline placeholder price), so it may misstate the real cost.

<details><summary>Caveats</summary>

Expand Down
2 changes: 1 addition & 1 deletion testdata/golden/monorepo-with-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

**Project total: $0/mo**

> ⚠️ **3 caveats:** parts of this estimate rest on assumptions (a price from another region, usage not provided, an attribute that could not be evaluated), so it may misstate the real cost.
> ⚠️ **3 caveats:** parts of this estimate rest on assumptions (an offline placeholder price), so it may misstate the real cost.

<details><summary>Caveats</summary>

Expand Down
2 changes: 1 addition & 1 deletion testdata/golden/multi-cloud.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

**Project total: $0/mo**

> ⚠️ **8 caveats:** parts of this estimate rest on assumptions (a price from another region, usage not provided, an attribute that could not be evaluated), so it may misstate the real cost.
> ⚠️ **8 caveats:** parts of this estimate rest on assumptions (an offline placeholder price), so it may misstate the real cost.

<details><summary>Caveats</summary>

Expand Down
2 changes: 1 addition & 1 deletion testdata/golden/vpc-stack.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@

**Project total: $10.95/mo**

> ⚠️ **13 caveats:** parts of this estimate rest on assumptions (a price from another region, usage not provided, an attribute that could not be evaluated), so it may misstate the real cost.
> ⚠️ **13 caveats:** parts of this estimate rest on assumptions (an offline placeholder price), so it may misstate the real cost.

<details><summary>Caveats</summary>

Expand Down
Loading