From 3e0d3d5ebfc40706cc2b846e9cab6b38739e2738 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 21 Sep 2026 22:12:27 +0200 Subject: [PATCH] Keep the home memo form when the decision overview fails The overview is orientation only; a store, policy or engine failure while listing now shows a notice instead of an error page, so the memo form and sign-out stay reachable. Co-Authored-By: Claude Opus 5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 359683@bnt-lap001 Assistant-Session: eebdc939-7a9b-4e50-9d39-c8437e8a14ec --- informed_decision/web.py | 15 ++++++++++++++- tests/test_review_controller.py | 8 ++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/informed_decision/web.py b/informed_decision/web.py index 6730947..b3ea736 100644 --- a/informed_decision/web.py +++ b/informed_decision/web.py @@ -188,7 +188,7 @@ class App: if method == "GET" and path == "/": if session: content = (f"

Signed in as {html.escape(session.subject)}.

" - + (overview_section(self.review.overview(session)) if self.review is not None else '') + + (self._overview(session) if self.review is not None else '') + ('

Open a decision review

Enter the memo identifier supplied with your review request.

' '
' '
' if self.review is not None else @@ -201,6 +201,19 @@ class App: return 200, document("Informed Decision", content, session.subject if session else None), "text/html", [] return 404, "Not found.", "text/plain", [] + def _overview(self, session): + # The overview is orientation only. Its failure must never take the + # memo form, sign-out or an unresolved-entry recovery path with it. + try: + return overview_section(self.review.overview(session)) + except ReviewError as exc: + if exc.code == "session_expired": + raise + except (PolicyError, ApprovalEngineError, StoreError, sqlite3.Error, ValueError, KeyError, TypeError): + pass + return ('

Your decisions

Your decisions could not be ' + 'listed right now. You can still open a review by its memo identifier.
') + def _form(self, environ, session): if environ.get("HTTP_ORIGIN") != ORIGIN: raise ReviewError(403, "invalid_form") diff --git a/tests/test_review_controller.py b/tests/test_review_controller.py index eda21b9..f737cd7 100644 --- a/tests/test_review_controller.py +++ b/tests/test_review_controller.py @@ -407,3 +407,11 @@ def test_home_without_session_shows_sign_in_only(review): r=call(app,'/') assert 'Sign in with KeyCape' in r['body'] and 'Your decisions' not in r['body'] assert controller.store.policy_observations()==[] + + +def test_home_keeps_the_memo_form_when_the_overview_fails(review,monkeypatch): + controller,session,app,*_=review + def broken(subject):raise sqlite3.OperationalError('disk') + monkeypatch.setattr(controller.store,'memos_for',broken) + r=home(review) + assert r['status']==200 and 'could not be listed right now' in r['body'] and 'Open a decision review' in r['body']