Render the my-decisions overview on the signed-in home page (INFD-WP-0003 T03)

Groups the reviewer's memos (needs attention, open, accepted, declined,
returned, closed, not available) above the manual memo-id form. Server
rendered and escaped; refused rows show only the memo id. The Chromium
harness gains a home-overview check (13 checks pass).

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
This commit is contained in:
tegwick 2026-09-21 22:07:08 +02:00
parent 39e5366abc
commit bd6c004f1a
5 changed files with 100 additions and 3 deletions

View file

@ -120,3 +120,55 @@ def review_page(page, session):
+ f'<aside class="card"><h2>What this act covers</h2><dl>{facts}<dt>Person being bound</dt>'
f'<dd>{text(memo.binding.principal.display_name)} · {text(session.subject)}</dd></dl>{evidence}</aside></div>')
return document(memo.question, content, session.subject)
OVERVIEW_GROUPS = {
"attention": ("Needs attention", "An approval entry may have reached Approval Engine without confirmation. Do not submit again; open the original record."),
"open": ("Open for you", "These memos await your response."),
"accepted": ("Accepted", "Approval Engine confirmed your approval entry. An approval does not authorize execution."),
"declined": ("Declined", "You declined these memos."),
"returned": ("Returned or in discussion", "You returned these memos or asked for discussion. A revised version reopens the question."),
"closed": ("Closed without your response", "The approval closed before you responded."),
"unavailable": ("Not available", "These memos are addressed to you but cannot be shown now."),
}
OVERVIEW_REASONS = {
"policy_denied": "The permission service refused access to this memo.",
"renderer_changed": "This memo names an earlier review interface.",
"unsupported_review_profile": "This memo requires a different review profile.",
"missing_act_binding": "This memo is not bound to an approval.",
"binding_changed": "The approval no longer matches this memo.",
"engine_unavailable": "Approval status is unavailable. The review checks it again before you act.",
}
def _overview_row(row):
link = "/review?memo_id=" + quote(row.memo_id, safe="")
if row.memo is None:
reason = OVERVIEW_REASONS.get(row.reason, "The permission check could not complete. Reload later.")
return (f'<div class="record"><strong>{text(row.memo_id)}</strong>'
f'<p class="muted">{text(reason)}</p></div>')
facts = [f'Memo {text(row.memo_id)} · version {row.memo.version}']
if row.engine_status:
facts.append(f'Approval status: {text(row.engine_status)}')
elif row.reason:
facts.append(text(OVERVIEW_REASONS.get(row.reason, "Approval status is unavailable.")))
if row.intent and row.intent.get("approved_at"):
facts.append(f'Entry recorded {text(row.intent["approved_at"])}')
history = ''.join(f'<li>{text(d.verb.value.capitalize())} · version {d.memo_version} · {text(d.at)}'
+ (f' · {text(s["state"])}' if s else '') + '</li>' for d, s in row.history)
return (f'<div class="record"><a href="{link}"><strong>{text(row.memo.question)}</strong></a>'
f'<p class="muted">{" · ".join(facts)}</p>'
+ (f'<details><summary>Your responses</summary><ul>{history}</ul></details>' if history else '')
+ '</div>')
def overview_section(rows):
if not rows:
return '<h1>Your decisions</h1><p>No decision memos are addressed to you.</p>'
sections = ''
for group, (label, explanation) in OVERVIEW_GROUPS.items():
members = [r for r in rows if r.group == group]
if members:
sections += (f'<section class="card"><h2>{label} ({len(members)})</h2>'
f'<p class="muted">{explanation}</p>' + ''.join(map(_overview_row, members)) + '</section>')
return '<h1>Your decisions</h1>' + sections