You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
An invalid decision record crashes decisions show/approve/list with exit 1 instead of a typed error #41
DecisionStore.load (sdk/src/cloudfall/decision.py) validates a stored decision record with catalog.validate_named(DECISION_SCHEMA, document) and lets the schema error escape. A record on disk that fails the schema makes cloudfall decisions show <id>, decisions approve <id>, decisions list and why exit 1 instead of answering with a typed error envelope. One example is a hand-edited approval.via with a value that isn't terminal or unknown.
Found while reviewing #37. It is already true on main for any invalid record, not only the new via field.
A record that fails the schema answers with a typed error (for example RECORD_INVALID) that names the file and the failing path, with its own exit code. decisions list and why must not hide one bad record behind a crash.
DecisionStore.load (sdk/src/cloudfall/decision.py) calls catalog.validate_named(DECISION_SCHEMA, document) and lets the schema library's ValidationError escape. The commands only catch DecisionError, so the error never reaches their RECORD_INVALID mapping and the CLI exits 1 with no envelope
The same happens one step earlier for a file that isn't JSON: json.loads raises JSONDecodeError, also uncaught
decisions list loads every record through load, so one bad file breaks the whole list, and why and decisions approve go through the same path
Plan. No new exit code is needed: decisions list, decisions show, decisions approve and why already declare RECORD_INVALID and map DecisionError to it (_record_invalid in sdk/src/cloudfall/app.py). load will turn a malformed or schema-invalid record into a DecisionError with a new code decision_record_invalid, whose message names the file and the failing JSON path. decisions list and why stay fail-fast: they answer RECORD_INVALID naming the bad file instead of skipping it, so a broken record is never hidden. Regression tests cover a non-JSON file, a bad status, and a bad approval.via, for show, list, approve and why.
PR: #43. DecisionStore.load now turns a record that isn't JSON (or isn't UTF-8) or fails the schema into RECORD_INVALID (exit 86, code decision_record_invalid), naming the file and the failing field. decisions show, list, approve and why all answer with it; approve refuses before asking anyone to type the id. list and why still stop at the first bad record instead of skipping it, as planned. CI is green; it goes to review and merge next.
Activity
shipmill-romamo commentedon Oct 8, 2026
Triage: implement
Confirmed on
main(964d889):DecisionStore.load(sdk/src/cloudfall/decision.py) callscatalog.validate_named(DECISION_SCHEMA, document)and lets the schema library'sValidationErrorescape. The commands only catchDecisionError, so the error never reaches theirRECORD_INVALIDmapping and the CLI exits 1 with no envelopejson.loadsraisesJSONDecodeError, also uncaughtdecisions listloads every record throughload, so one bad file breaks the whole list, andwhyanddecisions approvego through the same pathPlan. No new exit code is needed:
decisions list,decisions show,decisions approveandwhyalready declareRECORD_INVALIDand mapDecisionErrorto it (_record_invalidinsdk/src/cloudfall/app.py).loadwill turn a malformed or schema-invalid record into aDecisionErrorwith a new codedecision_record_invalid, whose message names the file and the failing JSON path.decisions listandwhystay fail-fast: they answerRECORD_INVALIDnaming the bad file instead of skipping it, so a broken record is never hidden. Regression tests cover a non-JSON file, a badstatus, and a badapproval.via, forshow,list,approveandwhy.shipmill-romamo commentedon Oct 8, 2026
PR: #43.
DecisionStore.loadnow turns a record that isn't JSON (or isn't UTF-8) or fails the schema intoRECORD_INVALID(exit 86, codedecision_record_invalid), naming the file and the failing field.decisions show,list,approveandwhyall answer with it;approverefuses before asking anyone to type the id.listandwhystill stop at the first bad record instead of skipping it, as planned. CI is green; it goes to review and merge next.shipmill-romamo commentedon Oct 9, 2026
Released in v0.6.0rc7.