diff --git a/deploy/README.md b/deploy/README.md index adf2061..2e169d0 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -164,11 +164,12 @@ The installed `informed-decision-admin` supports local custody operations only: ```sh informed-decision-admin inspect --db /data/private/review.sqlite -informed-decision-admin backup --db /data/private/review.sqlite --output /backup/private/review.sqlite +informed-decision-admin backup --db /data/private/review.sqlite --output /data/private/review-YYYYMMDD.sqlite ``` The backup parent must already be owned/private 0700; the destination must not -exist. Backup uses SQLite's consistent backup API while the service may be live. +exist. The deployment mounts no `/backup` volume; `/data/private` qualifies but +shares the PVC, so copy the file off-cluster (`kubectl cp`) for an independent copy. Backup uses SQLite's consistent backup API while the service may be live. Do not copy a running SQLite file while ignoring WAL. Inspection prints counts and schema version, not memo content or credentials. These are privileged operator custody commands, not browser endpoints. An independent backup copy, diff --git a/deploy/sitting-admission.json b/deploy/sitting-admission.json index c168ab7..d72b9a5 100644 --- a/deploy/sitting-admission.json +++ b/deploy/sitting-admission.json @@ -1,5 +1,5 @@ { - "image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:ef6fdd61209863654be3adba070661645a2714e86cb4b7f4e847540291b55f07", + "image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:971e88e3c7b68b370f4d7ef14824cc0e19c854b5aeb372e7ec7edbcf2c847b31", "policy": { "origin": "http://flex-auth-informed-decision-sitting.flex-auth.svc.cluster.local:8080", "package": "informed-decision.compact-sitting", diff --git a/deploy/t03-admission.json b/deploy/t03-admission.json index 0ae98f0..29a22ae 100644 --- a/deploy/t03-admission.json +++ b/deploy/t03-admission.json @@ -1,5 +1,5 @@ { - "image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:ef6fdd61209863654be3adba070661645a2714e86cb4b7f4e847540291b55f07", + "image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:971e88e3c7b68b370f4d7ef14824cc0e19c854b5aeb372e7ec7edbcf2c847b31", "policy": { "origin": "http://flex-auth-informed-decision-t03.flex-auth.svc.cluster.local:8080", "package": "informed-decision.t03-review", diff --git a/docs/evidence/2026-09-21-decision-overview-image.json b/docs/evidence/2026-09-21-decision-overview-image.json new file mode 100644 index 0000000..b92a7e2 --- /dev/null +++ b/docs/evidence/2026-09-21-decision-overview-image.json @@ -0,0 +1,30 @@ +{ + "task": "INFD-WP-0003", + "source_commit": "3e0d3d5", + "change": "Signed-in home page lists the reviewer's decision memos grouped as needs attention, open, accepted, declined, returned, closed or not available, with fallback to the memo form if listing fails. UI_RELEASE unchanged (informed-decision@0.2.0); store schema unchanged (v2); no new write path.", + "validation": "433 tests passed with actual Approval Engine, Audit Core and Flex Auth; Chromium harness 13/13; container smoke 11/11; Trivy 0.74.0 HIGH/CRITICAL: 0 findings.", + "image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:971e88e3c7b68b370f4d7ef14824cc0e19c854b5aeb372e7ec7edbcf2c847b31", + "previous_live_image": "forgejo.coulomb.social/coulomb/informed-decision@sha256:ef6fdd61209863654be3adba070661645a2714e86cb4b7f4e847540291b55f07", + "published": true, + "rolled_out": true, + "remaining": "Human sign-in view of the overview not yet observed by the agent.", + "rollout": { + "by": "operator", + "strategy": "Recreate via kubectl set image", + "pre_rollout_inspect": { + "schema_version": 2, + "outbox": { + "delivered": 50 + }, + "submissions": { + "confirmed": 7 + } + }, + "pre_rollout_backup": "/data/private/review-20260921-pre-overview.sqlite (same PVC; consistent_snapshot true)", + "post_rollout": { + "ready_replicas": 1, + "healthz": "ok", + "readyz": "ready" + } + } +} 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 '') + ('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 ('