Skip to content

pkg/health: constraints_wellformed signal (parse-only, hermetic) #1227

Description

@njhensley

Parent: #1224 (Epic: Recipe health tracking, ADR-009 V1)

Summary

Add the third graded signal, constraints_wellformed, hermetically.

ADR-009's original phrasing ("inline replay under --no-cluster is clean") is not achievable offline: the only evaluator, pkg/constraints.Evaluate(constraint, *snapshotter.Snapshot), calls path.ExtractValue(snap) before parsing, and the sole wiring rejects a nil snapshot (pkg/client/v1/aicr.go). With no snapshot — ADR-009's hermetic premise — there is no "clean replay" to run. So the V1 signal is parse-only well-formedness.

Scope

  • Primary (graded, fully hermetic): for every merged Constraint, call the exported, snapshot-free parsers directly — ParseConstraintPath(c.Name) (pkg/constraints/extractor.go) and ParseConstraintExpression(c.Value) (pkg/constraints/constraint.go). Any parse failure → fail, with the offending constraint + parser error in Detail.
  • Secondary (graded warn, hermetic): resolve the leaf via BuildFromCriteriaWithEvaluator with an injected stub ConstraintEvaluatorFunc (a plain func(Constraint) ConstraintEvalResult, trivially mockable) returning a deterministic satisfied result so the constraint-aware path executes without cluster data. Surface any resulting RecipeResult.Metadata.ConstraintWarnings/ExcludedOverlays as warn. Hermetically this catches resolution/evaluation-setup problems and mixin-composition inconsistencies — not cluster-dependent constraint outcomes.
  • Fail honestly: a malformed constraint is fail, never a silent pass.
  • Fold the signal into the pkg/health: core Compute() loop, resolves signal, rollup, determinism #1225 rollup.

Seam note

A3 needs no pkg/validator import. The acyclic integration is pkg/health → pkg/constraints → pkg/recipe. (The stale pkg/recipe/builder.go doc comment "wrapping validator.EvaluateConstraint" references a symbol that does not exist; flag for a separate one-line fix.)

Out of scope (deferred)

Snapshot-dependent constraint replay (actual pass/fail against cluster/snapshot state) — non-hermetic; belongs with the validation/evidence axis (coverage_declared_vs_run). Pull-trigger: the validation axis lands and a snapshot is available to the generator.

Tests

Malformed Constraint.Value/.Namefail (exercises the parser, snapshot-free); a leaf whose stub-evaluator resolution surfaces a ConstraintWarningwarn with Detail; a clean recipe → pass. Stub evaluator is a table-driven fake; no pkg/validator or cluster dependency.

Acceptance

constraints_wellformed grades on parse-only well-formedness hermetically, surfaces resolution warnings, never silently passes a malformed constraint, and the four-dimension rollup is correct end-to-end. Snapshot replay is explicitly deferred.

Dependencies

Depends on #1225 (rollup) / #1226. Consumed by #1228 and #1229.

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions