feat(state): chant state diff --live drift detection (#26)#32
Merged
Conversation
Adds createMockPlugin() and staticDescribeResources() helpers used by upcoming live-diff tests (#26) and reusable for future state/run handler tests (#29). Lifecycle methods are no-ops; describeResources is wired through when provided so tests can simulate live cloud responses without real cloud access.
Pure-function comparator that classifies resources across three axes: declared (entity names from current build), observedNow (from plugin.describeResources()), and observedThen (from previous snapshot). Produces six categories: missing (declared, not observed), orphan (observed, not declared), disappeared (in previous snapshot, gone now), newlyObserved (declared, observed, no prior snapshot), driftedSinceSnapshot (metadata diff between snapshots), and unchanged. Drift items carry attribute-level changes for status, physicalId, lastUpdated, and each attributes.* key. No I/O — caller wires plugins, snapshot reads, and rendering. Eight unit tests covering each category and a mixed scenario.
Adds --live flag (parsed in cli/main.ts, ParsedArgs.live) that switches state diff from digest comparison to a live cloud query against the previous snapshot. Per lexicon: declared (entity names) ↔ observedNow (plugin.describeResources) observedNow ↔ observedThen (snapshot.resources) Renders six categories: missing, orphan, disappeared, newly observed, drifted (with attribute-level changes), and unchanged. Lexicons without describeResources are warn-skipped, not failed. Default behavior (without --live) is unchanged — the digest path stays for fast, offline-friendly checks. Three handler tests cover the drift, warn-skip, and legacy paths.
@intentius/chant isn't a real workspace dep of @intentius/chant-test-utils; the existing fixtures.ts uses ../../core/src/* relative imports for the same reason. Match that convention so vitest can resolve types.
Splits the state diff section into two modes: default (digest, fast and offline) and --live (calls describeResources(), reports the six drift categories). Documents the warn-skip behavior for lexicons that don't implement describeResources() and links to issue #27 for tracking lexicon coverage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #26. Implements
chant state diff <env> --live— a live-cloud drift mode that catches external mutations the existing digest-only diff misses. Default (digest) behavior is unchanged;--liveis opt-in for v1.The new path:
Six categories per lexicon: missing, orphan, disappeared, newly observed, drifted (with attribute-level changes), and unchanged. Lexicons without
describeResources()are warn-skipped, not failed.Commits
chore(test-utils): add mockPlugin factory— reusable for Zero tests on cli/handlers/{state,run,graph}.ts — refactoring is unsafe #29feat(state): live-diff comparator— pure function inpackages/core/src/state/live-diff.ts, 8 unit testsfeat(cli): wire --live into state diff— flag plumbing + handler split intorunStateDiffLive/runStateDiffDigest, 3 handler testsdocs(state): document state diff --live drift modefix(test-utils): use relative imports in mockPlugin factory— small follow-upWhat's intentionally not in this PR
--livethe default (would need broaderdescribeResources()coverage; tracked in Temporal lexicon doesn't implement describeResources() — state snapshot skips Temporal entirely #27)describeResources()— that's Temporal lexicon doesn't implement describeResources() — state snapshot skips Temporal entirely #27Verification
just buildcleannpx vitest run packages/core/ packages/test-utils/→ 1434/1434 pass (16 new tests)state diff(no--live) still works — regression test includeddescribeResources()is the path that will exercise this in productionTest plan
--liveincludes Temporal coverage too