feat(health): chart_pinned signal + declared_coverage descriptor#1293
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Enterprise Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR implements two new health signals for recipe validation: Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pkg/health/health.go`:
- Around line 118-121: The struct field Coverage is defined as a non-pointer
without omitempty so unresolved recipes emit a zero-valued coverage object;
change the field to a pointer (e.g., Coverage *DeclaredCoverage
`json:"coverage,omitempty" yaml:"coverage,omitempty"`) and update any code that
populates it (the resolver that currently computes DeclaredCoverage at
Resolve/RecipeResult creation around the logic referenced at lines 223-224) to
allocate and assign a pointer when the coverage is available (e.g., set Coverage
= &computedCoverage) and leave it nil on failure/hold so the JSON/YAML omits the
key as intended.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: ea9f9acb-d3ca-4dc7-9d56-f7c613a09ef4
📒 Files selected for processing (3)
pkg/health/doc.gopkg/health/health.gopkg/health/health_test.go
Coverage Report ✅
Coverage BadgeMerging this branch will increase overall coverage
Coverage by fileChanged files (no unit tests)
Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code. |
Code ReviewScope: 🔴 BlockerNone. 🟠 Major — should fix before merge1. A disabled Helm component left unpinned would score for _, ref := range result.ComponentRefs {
if ref.Type != recipe.ComponentTypeHelm || !ref.IsEnabled() {
continue
}
...
}Impact today is latent — no current recipe disables a component — so not a hard blocker. But health exists to catch exactly this class of mistake, and emitting a false 🟡 Medium / Questions2. 3. Is vacuous 🔵 Low / Nits4. 5. Three-way distinction downstream. For ✅ Strengths (verified)
VerdictApprove pending the disabled-component fix (#1). Everything else is a question or nit. Recommend: add the |
Layer the two pure-read structural signals onto the pkg/health core (ADR-009 V1), both computed only when a leaf resolves cleanly: - chart_pinned (graded): every enabled Helm component must reference an explicit chart version (ADR-006 layer 1 — chart-version presence check, not image digests; no Helm render). An unpinned enabled Helm component fails and drags the rolled-up status to fail. Disabled components (overrides.enabled: false) are skipped — they are never bundled or deployed, matching every other ComponentRefs consumer. A recipe with no enabled Helm components scores a vacuous pass with an explanatory Detail, since Kustomize tag pinning is out of scope and the column must not be misread as supply-chain pinned. - declared_coverage (descriptor, never graded): per validation phase, record whether the phase is declared, its sorted named checks, and its phase-level constraint count. A minimal recipe that drops phases is not penalized. The descriptor is a pointer, omitted on a failed/held resolve rather than emitting a misleading all-zero block. chart_pinned feeds the existing generic rollup unchanged. Adds unit tests for both signals (including disabled-component skip) plus end-to-end tests driving a real chart_pinned fail and asserting the coverage omit/populate contract through the builder. Closes #1226
0cd52c7 to
5fb5b02
Compare
|
Thanks for the thorough review — addressed in #1 (Major — disabled components): fixed. #2 (Medium — non-empty vs exact-pin): confirmed + documented. ADR-006 layer 1 is "pin chart versions for every Helm component" and issue #1226 specifies the check as non-empty #3 (Question — vacuous #4 (Nit — stale #5 (Nit — three-way distinction for the renderer): noted in code. Added a paragraph to Also folded in CodeRabbit's contract fix: |
njhensley
left a comment
There was a problem hiding this comment.
Re-reviewed at 5fb5b024 — all prior findings resolved. ✅
- #1 (Major, disabled components): fixed —
classifyChartPinnedskips!ref.IsEnabled(),helmCountcounts only enabled, vacuous-pass keys off enabled Helm count; two new unit cases added. Matches the bundler/deployer/mirror/BOM convention. - #2 / #3 / #4 / #5: confirmed + documented (presence-check comment, vacuous-pass per #1226, corrected
Detaildoc, three-state renderer note). - CodeRabbit
Coveragepointer fix reviewed independently and sound:*DeclaredCoverage+omitempty, assigned only on clean resolve, distinguishing "resolved, declares nothing" from "unknown"; both ends tested.
CI fully green (Test, Lint, E2E, CLI E2E, Security Scan, CodeRabbit, Analyze); pkg/health 97.6%, project 76.5% (> 75% gate). Tightly scoped, correct, consistent with the codebase.
Summary
Layers the two pure-read structural signals onto the
pkg/healthcore (ADR-009 V1), both computed only when a leaf resolves cleanly:chart_pinned(graded) anddeclared_coverage(descriptor).Motivation / Context
Next step of the Recipe health tracking epic (ADR-009 V1), building directly on the merged core (#1225). These are the two signals that are pure reads of the resolved
RecipeResult— no external integration, no Helm render.Fixes: #1226
Related: #1224 (epic), #1225 (core, merged), #1227, #1228, #1229
Type of Change
Component(s) Affected
pkg/recipe) —pkg/healthonly (readsRecipeResult)Implementation Notes
chart_pinned(graded): iterateRecipeResult.ComponentRefs; everyType == ComponentTypeHelmmust have a non-emptyVersion. Any unpinned Helm component →fail(offending names sorted intoDetail), dragging the rolled-up status tofail. ADR-006 layer 1 only — the chart-version pin, not image digests; pure field check, no render. A recipe with no Helm components (pure-Kustomize/empty) scores a vacuouspasswith an explanatoryDetail, since KustomizedefaultTagpinning is out of scope and the column must not be misread as "supply-chain pinned". Feeds the existing generic rollup unchanged.declared_coverage(descriptor, never graded): fromRecipeResult.Validation.{Readiness,Deployment,Performance,Conformance}, record per phaseDeclared bool, sortedChecks []string, andlen(Constraints). Lives inStructureHealth.Coverage(a separate field, not in theDimensionsmap), so it can never move the status — a minimal recipe that drops phases is not penalized.RecipeResultto read otherwise); a failed/held combo carries neither.Checksare sorted; pass-pathDetailis a static string only in the vacuous-Kustomize case.Testing
classifyChartPinned(all-pinned pass; unpinned fail with sorted names; pure-Kustomize vacuous pass; mixed);computeCoverage/phaseCoverage(nil → zero, sorted checks, undeclared phases not penalized).resolves=pass) butchart_pinned=fail→ statusfailwith the component named inDetail.pkg/healthcoverage: 97.6% (was 95.8%; new helpers fully covered).Risk Assessment
pkg/health, no user-facing surface (CLI/docs/matrix rendering land in aicr recipe list: add structural-health + coverage columns #1228/tools/health generator + make targets + public recipe-health matrix #1229).Rollout notes: N/A
Checklist
make testwith-race)make lint)git commit -S)