Compare commits

...

3 commits

Author SHA1 Message Date
77792fa4f5 Record the decision-overview rollout and pin its image in admission inputs
Operator rolled out sha256:971e88e3 after a pre-rollout inspect (7 confirmed,
no unresolved submissions) and an in-volume backup. README backup path now
matches the deployment, which mounts no /backup volume.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 359683@bnt-lap001
Assistant-Session: eebdc939-7a9b-4e50-9d39-c8437e8a14ec
2026-09-21 22:32:19 +02:00
ac0a4e2fb0 Record the published decision-overview image (not yet rolled out)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 359683@bnt-lap001
Assistant-Session: eebdc939-7a9b-4e50-9d39-c8437e8a14ec
2026-09-21 22:16:02 +02:00
3e0d3d5ebf 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 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 359683@bnt-lap001
Assistant-Session: eebdc939-7a9b-4e50-9d39-c8437e8a14ec
2026-09-21 22:12:27 +02:00
6 changed files with 57 additions and 5 deletions

View file

@ -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,

View file

@ -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",

View file

@ -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",

View file

@ -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"
}
}
}

View file

@ -188,7 +188,7 @@ class App:
if method == "GET" and path == "/":
if session:
content = (f"<p>Signed in as {html.escape(session.subject)}.</p>"
+ (overview_section(self.review.overview(session)) if self.review is not None else '')
+ (self._overview(session) if self.review is not None else '')
+ ('<h2>Open a decision review</h2><p>Enter the memo identifier supplied with your review request.</p>'
'<form method="get" action="/review"><label>Memo identifier <input name="memo_id" required maxlength="256"></label>'
'<button type="submit">Open review</button></form>' 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 ('<h1>Your decisions</h1><div class="notice warning" role="status">Your decisions could not be '
'listed right now. You can still open a review by its memo identifier.</div>')
def _form(self, environ, session):
if environ.get("HTTP_ORIGIN") != ORIGIN:
raise ReviewError(403, "invalid_form")

View file

@ -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']