You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Parent:#1224 (Epic: Recipe health tracking, ADR-009 V1)
Summary
Stand up the new pkg/health package: the enumeration→resolution loop, the resolves signal, the status rollup with unknown-held semantics, and the determinism harness. The read-only signals are #1226; the constraint signal is #1227.
pkg/health is a standalone package (not in pkg/recipe) to keep the future v1.1 evidence import acyclic — pkg/evidence/attestation already imports pkg/recipe, so hosting health in pkg/recipe would later close a recipe → evidence → recipe cycle. V1 deps: pkg/recipe, pkg/serializer, pkg/errors, pkg/defaults.
Scope
New package pkg/health with the ADR-009 §4 types: Options, PhaseCoverage, DeclaredCoverage, StructureHealth, ComboHealth, Report, and SchemaVersion = "1.0.0".
func Compute(ctx, opts Options) (*Report, error): enumerate via MetadataStore.ListCatalog(nil) filtered to Curated == true (the merged feat(recipe): add aicr recipe list subcommand for catalog enumeration #1208 seam — each CatalogEntry gives Name → ComboHealth.LeafOverlay and Criteria), resolve each through a single sharedrecipe.NewBuilder(...)'s BuildFromCriteria (so the owner-stamp invariant holds across combos). ListCatalog is name-sorted (deterministic); consume as-is or re-sort by criteria tuple — either is deterministic.
resolves signal (graded, intrinsic to the loop): resolves → pass; non-transient error → fail (error in Detail); ErrCodeTimeout/ErrCodeInternal → unknown (held, excluded from rollup, never an empty field).
Add pkg/health/** to .github/CODEOWNERS and a pkg/health/** area glob to .github/labeler.yml.
Determinism
No time.Now() on the computed path. Caveat: the unknown-from-ErrCodeTimeout mapping is the one non-deterministic input — byte-determinism is asserted on the non-error path only; tests inject errors via a fake DataProvider, never real timeouts.
Clean recipe → pass; injected transient error (fake provider) → unknown held out of rollup; determinism: serialize the Report via the deterministic marshaller and assert byte-equality across two Compute runs (not struct DeepEqual — Report carries map[string]string, whose nondeterminism only manifests at marshal time); empty-catalog → empty Report, no panic.
Acceptance
pkg/health exists with Compute(), the resolves signal, a generic rollup with unknown-held, and a marshal-and-compare byte-determinism test. CODEOWNERS + labeler glob land here. 75% coverage floor cleared.
Parent: #1224 (Epic: Recipe health tracking, ADR-009 V1)
Summary
Stand up the new
pkg/healthpackage: the enumeration→resolution loop, theresolvessignal, the status rollup withunknown-held semantics, and the determinism harness. The read-only signals are #1226; the constraint signal is #1227.pkg/healthis a standalone package (not inpkg/recipe) to keep the future v1.1 evidence import acyclic —pkg/evidence/attestationalready importspkg/recipe, so hosting health inpkg/recipewould later close arecipe → evidence → recipecycle. V1 deps:pkg/recipe,pkg/serializer,pkg/errors,pkg/defaults.Scope
pkg/healthwith the ADR-009 §4 types:Options,PhaseCoverage,DeclaredCoverage,StructureHealth,ComboHealth,Report, andSchemaVersion = "1.0.0".func Compute(ctx, opts Options) (*Report, error): enumerate viaMetadataStore.ListCatalog(nil)filtered toCurated == true(the merged feat(recipe): add aicr recipe list subcommand for catalog enumeration #1208 seam — eachCatalogEntrygivesName→ComboHealth.LeafOverlayandCriteria), resolve each through a single sharedrecipe.NewBuilder(...)'sBuildFromCriteria(so the owner-stamp invariant holds across combos).ListCatalogis name-sorted (deterministic); consume as-is or re-sort by criteria tuple — either is deterministic.resolvessignal (graded, intrinsic to the loop): resolves →pass; non-transient error →fail(error inDetail);ErrCodeTimeout/ErrCodeInternal→unknown(held, excluded from rollup, never an empty field).failif any graded dimension fails; elsewarn; elsepass.unknownis held. The rollup iteratesDimensionsgenerically so pkg/health: chart_pinned + declared_coverage signals #1226/pkg/health: constraints_wellformed signal (parse-only, hermetic) #1227 add dimensions without changing rollup code.pkg/health/**to.github/CODEOWNERSand apkg/health/**area glob to.github/labeler.yml.Determinism
No
time.Now()on the computed path. Caveat: theunknown-from-ErrCodeTimeoutmapping is the one non-deterministic input — byte-determinism is asserted on the non-error path only; tests inject errors via a fakeDataProvider, never real timeouts.Key files
pkg/recipe/catalog.go(ListCatalog,CatalogEntry— from #1208),pkg/recipe/builder.go(NewBuilder,BuildFromCriteria),pkg/recipe/metadata.go(RecipeResult),pkg/serializer(deterministic marshal).Tests
Clean recipe →
pass; injected transient error (fake provider) →unknownheld out of rollup; determinism: serialize theReportvia the deterministic marshaller and assert byte-equality across twoComputeruns (not structDeepEqual—Reportcarriesmap[string]string, whose nondeterminism only manifests at marshal time); empty-catalog → emptyReport, no panic.Acceptance
pkg/healthexists withCompute(), theresolvessignal, a generic rollup withunknown-held, and a marshal-and-compare byte-determinism test. CODEOWNERS + labeler glob land here. 75% coverage floor cleared.Dependencies
Builds on the merged
MetadataStore.ListCatalog(#1208). Blocks #1226, #1227, #1228, #1229.