Repository navigation
Answer RECORD_INVALID for an invalid decision record - #43
Merged
Merged
Conversation
DecisionStore.load let JSONDecodeError and the schema library's ValidationError escape, so decisions show/list/approve and why crashed with exit 1 and no envelope. Both now raise DecisionError with code decision_record_invalid, naming the file and the failing field. Fixes #41 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
What changed
DecisionStore.load(sdk/src/cloudfall/decision.py) now turns a broken record into aDecisionErrorwith the new codedecision_record_invalid(_ERROR_RECORD_INVALID):json.JSONDecodeError, orUnicodeDecodeErrorfor bytes that are not UTF-8): the message names the file and the parser's errorjsonschemaValidationError): the message names the file, the failing JSON path (e.g.spec.approval.via,(root)for the top level) and the validator's messageOnly those exception types are caught, each chained with
from error.Behaviour changes
decisions show,decisions list,decisions approveandwhyanswerRECORD_INVALID(exit 86) withcontext.code = decision_record_invalidfor an invalid record, instead of crashing with exit 1 and no envelope. All four already declaredRECORD_INVALIDand mappedDecisionErrorto it, so no exit-code or command change was neededdecisions approveloads the record before asking the person to type the id, so a broken record is refused before any prompt or rundecisions listandwhystay fail-fast: the first bad record answersRECORD_INVALIDnaming that file; nothing is skippeddecisions list/showthrough the same handlers, so it gets the same typed error. Theoperatorcommands andagentpaths useProposalStore, notDecisionStore, and are unaffected.propose/approveindecision.pyonly write (save/update), neverloadTests
sdk/tests/test_decision.py:test_an_invalid_record_answers_record_invalid_naming_the_file: a non-JSON file, a badspec.statusand a badspec.approval.via, each throughshow,list,approveandwhy(12 cases); asserts exit 86,RECORD_INVALID,decision_record_invalid, and that the message names the file and the failing fieldtest_a_store_refuses_an_invalid_record_with_a_decision_error:DecisionStore.list()raisesDecisionErrorfor a bad recordChecks run locally:
uv sync,uv run ruff check .,uv run mypy,uv run pytest(416 passed),uv run cloudfall config validate --project config/examples.ruff format --checkis not a CI step (51 files already differ on main), so it was not applied.CHANGELOG: one line under
[Unreleased]→Fixed.Fixes #41
Decisions for you
None. The plan on the issue was followed as published. One small addition: a record that is not valid UTF-8 is treated like a non-JSON file (same code), since
read_textwould otherwise crash the same way.🤖 Generated with Claude Code