Skip to content

Adopt typed compare engine output and remove legacy violation contract#105

Merged
corymhall merged 2 commits intomasterfrom
st-ac3.17.3.1-typed-change-engine
Mar 2, 2026
Merged

Adopt typed compare engine output and remove legacy violation contract#105
corymhall merged 2 commits intomasterfrom
st-ac3.17.3.1-typed-change-engine

Conversation

@corymhall
Copy link
Member

@corymhall corymhall commented Feb 27, 2026

Summary

This PR establishes typed Change items as the canonical output of the internal compare engine.

It replaces violation plumbing with a typed-first contract that downstream renderers can consume directly.

What Changed

  • Reworked internal/compare model and engine output to emit typed change records.
  • Removed legacy violation-oriented report fields and bridging logic.
  • Strengthened engine/requiredness tests around deterministic typed output and removed-output edge cases.
  • Kept category semantics explicit in one place so later PRs can project/render from a stable contract.

Why

The stack needs a single canonical change model before projection/rendering and lookup normalization can be simplified safely.

This is the foundation for follow-up projection and lookup integration work in #106 and above.

Copy link
Contributor

@guineveresaenger guineveresaenger left a comment

Choose a reason for hiding this comment

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

I've got a few comments but they may be because I haven't worked my way all the way down the PR stack yet.

*changes = append(*changes, newChange(category, name, path, ChangeKindTypeChanged, fmt.Sprintf("type changed from %q to %q", oldType, newType)))
}

appendTypeChanges(changes, category, name, append(slicesClone(path), "items"), old.Items, new.Items)
Copy link
Contributor

Choose a reason for hiding this comment

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

is slicesClone just for safety?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, exactly for path-slice safety during recursive append(...) calls. I’ve now switched this over to stdlib slices.Clone so we keep the safety behavior without a custom helper.

appendTypeChanges(changes, category, name, append(slicesClone(path), "additional properties"), old.AdditionalProperties, new.AdditionalProperties)
}

func slicesClone(xs []string) []string {
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason not to use the stdlib https://pkg.go.dev/slices#Clone?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch, I thought I replaced all usages of this type of thing, but missed one!

Changes: changes,
NewResources: newResources,
NewFunctions: newFunctions,
Violations: BreakingChanges(oldSchema, newSchema),
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we looking at getting rid of this further down the PR stack? I'd think that breaking changes would ultimately be part of Changes? I'm asking because buildChanges is effectively the same walk that BreankingChanges does.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, that’s the direction. This PR introduces typed Changes while still keeping Violations to make this PR diff smaller. The downstream stack PRs remove the legacy path.

for _, req := range f.Outputs.Required {
_, stillExists := f.Outputs.Properties[req]
stillExists := false
if newFunc.Outputs != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be fixed separately?

Copy link
Member Author

Choose a reason for hiding this comment

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

I kept this here because it’s a correctness fix in the same compare logic path touched by this refactor. Without it, we can incorrectly report “required -> optional” when the output is actually removed. I added regression coverage for this case in engine_test.go.

newRequired := set.FromSlice(newTyp.Required)
for _, r := range typ.Required {
_, stillExists := typ.Properties[r]
_, stillExists := newTyp.Properties[r]
Copy link
Contributor

Choose a reason for hiding this comment

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

same - isn't this an unrelated change?

Copy link
Member Author

Choose a reason for hiding this comment

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

Similar reasoning here: this is a bug fix in requiredness gating (newTyp.Properties is the right source of truth for “still exists”). Keeping it with this change avoided carrying known-bad behavior into the typed engine transition, and it now has test coverage.

Base automatically changed from st-ac3.17-011-normalize-metadata-contract to master March 2, 2026 11:13
Squash details:
- Branch: st-ac3.17.3.1-typed-change-engine
- Base: st-ac3.17-011-normalize-metadata-contract
- Squashed commits: 5

Original commits:
- d437c23 internal/compare: emit typed change report
- b1c2126 internal/compare: make analyze typed-first contract
- b92c677 internal/compare: remove violations shim from report
- cc68ad5 internal/compare: restore compatibility and fix requiredness gating
- e576846 Fix requiredness gating for removed outputs and properties
@corymhall corymhall force-pushed the st-ac3.17.3.1-typed-change-engine branch from 5048446 to cf2f789 Compare March 2, 2026 11:16
@corymhall corymhall merged commit 05e962f into master Mar 2, 2026
5 checks passed
@corymhall corymhall deleted the st-ac3.17.3.1-typed-change-engine branch March 2, 2026 11:55
corymhall added a commit that referenced this pull request Mar 2, 2026
## Summary
This PR rebuilds compare projections and renderers to consume typed
change data directly.

It removes legacy rendering assumptions and aligns JSON/text output
contracts with the typed engine introduced in #105.

## What Changed
- Reworked compare projection logic to build structured `changes` and
`grouped` views from typed events.
- Updated JSON and text renderers to use the structured model
consistently.
- Removed dead legacy-engine artifacts from compare internals.
- Added/updated golden fixtures and renderer tests for deterministic
contract coverage.
- Added compare-level structured golden coverage for fixture parity.

## Why
Renderer/projection behavior should be derived from one typed source of
truth.

Doing this here makes later normalization lookups additive, instead of
requiring command-layer patchups.

## Context
- Builds directly on #105.
- Provides the projection baseline that later lookup-focused PRs rely
on.
corymhall added a commit that referenced this pull request Mar 2, 2026
…antics (#112)

## Summary
This PR finalizes the compare structured-output wave by aligning
contracts, goldens, and harness coverage across compare and cmd paths.

It also captures finalized output semantics for capped text rendering
and full structured JSON output.

## What Changed
- Finalized structured compare/cmd golden harness coverage for AWS mini
fixtures.
- Updated compare/cmd tests and fixture expectations to the finalized
contracts.
- Kept JSON structured output uncapped while keeping text output capped.
- Refined requiredness/remap severity/breaking classification to match
the final policy.
- Updated README/docs and supporting command/test plumbing required for
end-to-end parity.

## Why
This closes the loop on behavior, tests, and documentation so reviewers
can validate a stable end-state at the stack tip.

It ensures the same semantics are exercised by both compare package
tests and command harness tests.

## Context
- Final stack tip on top of #111.
- Consolidates contract/golden alignment after upstream engine and
lookup integrations (#105#111).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants