feat(cli): add early diagnostics to Construct [RED-641]#1355
Open
sorccu wants to merge 3 commits into
Open
Conversation
Constructs validate via async validate(), but are built through a sync constructor that cannot do async work and by convention does not throw for user-facing validation. Add an earlyDiagnostics collector on the base Construct that a constructor can record issues into; base validate() merges it into the caller's Diagnostics, so the issues flow through the existing per-construct collection and reporting path with no changes to subclasses or commands. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QBbrKMRZw7DjdqjSgnQX41
Closed
4 tasks
…-641] Turn two construction-time hard errors into soft validation diagnostics via the new earlyDiagnostics mechanism, so they're collected and reported alongside other validation issues instead of aborting with an exception: - A non-string logicalId is recorded as a diagnostic in the Construct constructor and the value is coerced to a string; the matching throw in Session.validateCreateConstruct is removed. - A duplicate logicalId is recorded as a diagnostic on the Project in addResource instead of throwing. The duplicate resource is intentionally not stored, so the diagnostic is attributed to the project to ensure it surfaces during validation. Removes the now-unused ValidationError class. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QBbrKMRZw7DjdqjSgnQX41
0f4089e to
35a7fa6
Compare
Temporary: trial Blacksmith Windows runners to work around the GitHub windows-latest fleet slowdown that pushes the e2e suite past its timeouts. Intended to be dropped before merge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QBbrKMRZw7DjdqjSgnQX41
625ed6d to
3478e40
Compare
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.
Why
Constructs validate via
async validate(diagnostics), but they're built through a synchronous constructor that can't do async work and, by convention, never throws for user-facing validation issues. Anything a constructor notices at construction time (e.g. an argument of the wrong type) currently has to either throw a hard error or be stashed in a single-purpose instance field solely sovalidate()can re-inspect it later.This adds a first-class way for a constructor to record diagnostics at construction time, then reimplements the invalid/duplicate
logicalIdvalidation on top of it.What
Commit 1 — infrastructure. Adds a
readonly earlyDiagnostics = new Diagnostics()collector on the baseConstruct. A constructor records issues into it; basevalidate()merges them into the caller'sDiagnosticsviadiagnostics.extend(this.earlyDiagnostics). Because every subclassvalidate()starts withawait super.validate(diagnostics), andProject.validate()already wraps each member inConstructDiagnostics, early diagnostics flow through the existing per-construct collection and reporting path with no changes to subclasses or commands.Commit 2 — example. Turns two construction-time hard errors into soft validation diagnostics using the new mechanism (no holder fields):
logicalIdis recorded as a diagnostic in theConstructconstructor and the value is coerced to a string; the matching throw inSession.validateCreateConstructis removed.logicalIdis recorded on theProjectinaddResourceinstead of throwing. The duplicate resource is intentionally not stored, so the diagnostic is attached to the project to ensure it surfaces during validation, and is wrapped in aConstructDiagnosticso the reported title names the offending construct (e.g.[CheckGroup:my-check-group]).ValidationErrorclass.These now surface as fatal validation diagnostics (non-zero exit) under
checkly validate/checkly deploy/checkly testrather than aborting with an unhandled exception.Tests
early-diagnostics.spec.tscovers the plain path, theConstructDiagnosticsattribution-prefix path, and the empty case.project.spec.tsgains non-string and duplicatelogicalIdcases; the duplicate case asserts the construct-attributed title prefix.logicalIde2e test now asserts the soft diagnostic on stdout with exit 1.tsc --buildclean; full constructs unit suite green.Resolves RED-641.
🤖 Generated with Claude Code