--- id: INFD-WP-0003 type: workplan title: "My decisions overview — pending memos and the outcome of past dispositions" domain: infotech repo: informed-decision status: finished owner: claude topic_slug: netkingdom created: "2026-09-21" updated: "2026-09-21" related: - INFD-WP-0001 - INFD-WP-0002 origin: demand origin_ref: "founder request 2026-09-21: review decisions taken, whether they were accepted, and which are still open" state_hub_workstream_id: "d47a50d6-d429-5018-8858-f721023ca579" --- # My decisions overview Founder request 2026-09-21: in the informed-decision UI, see (a) the decisions I have taken and whether they were accepted, and (b) the decisions still open for me to take. Today the signed-in home page offers only a free-text memo-identifier box (`informed_decision/web.py`, `GET /`). A person has to already know each memo id, and nothing shows the outcome of a past disposition unless that exact review is reopened. ## Why this does not breach the Stage 1 boundaries - **Not an approval-engine inbox.** The list is built from memos that informed-decision itself holds, addressed to the signed-in subject (`memo.binding.principal.id`). approval-engine is still called get-by-id only, for approval ids those memos already carry. It never polls for work. - **Not owned approval state.** Engine status is read live on each render and never stored. Local state is limited to our own evidence: the disposition and the submission correlation (`submissions.state`, `approved_at`). - **Not a decision point.** The overview decides nothing. Every row goes through the same fresh PDP `read` check that `ReviewController.open` uses before any memo content is rendered. If that check is denied or unavailable, the row shows the memo id and "not available" and nothing else (fail closed). - **Not a binding view.** The overview creates no presentation record. Binding still happens only on the existing review page. ## Row classification (latest memo version, addressed to me) | Group | Condition | |---|---| | **Needs attention** | submission `in_flight` / `unresolved`: outcome unconfirmed, operator recovery | | **Open for you** | no accept/decline by me on the latest version, no submission, engine status `requested`/`approved` | | **Decided — accepted** | submission `confirmed` (show `approved_at`) plus live engine status (`approved`, `consumed`, …) | | **Decided — declined** | decline disposition on the latest version | | **Returned / discussion** | return/discuss on the latest version with no newer version yet (awaiting revision) | | **Closed without you** | engine status `expired`/`revoked`/`superseded` and no disposition by me | Each row links to the existing review (`/review?memo_id=…`), which already recovers the original presentation when an intent exists. The earlier dispositions on older memo versions appear as a short history under the row. ## Store listing for the signed-in subject ```task id: INFD-WP-0003-T01 status: done priority: high state_hub_task_id: "2b878f29-492a-5187-a594-36a12aaa932d" ``` Add `Store.memos_for(subject)`, which returns the latest version of every memo whose binding principal is `subject` (a `person`). Add `Store.dispositions_by(subject, memo_id)`, which returns that subject's dispositions across all versions, together with any submission row. This is read-only. Tests go in `tests/test_durable_store.py`. ## Controller overview with per-row PDP read and live engine status ```task id: INFD-WP-0003-T02 status: done priority: high state_hub_task_id: "b4172f0c-7cd3-5780-bf50-62670df7e416" ``` Add `ReviewController.overview(session)`, which returns classified rows. Each row gets its own `_authorize(session, memo, "read")` and `get_approval`. A row whose PDP check fails is redacted to its id only. A failure of the approval engine on one row only degrades that row's status to "status unavailable". It never degrades the whole page. The overview never creates a presentation. Tests go in `tests/test_review_controller.py`, using the existing fakes: allow, deny, policy unavailable, engine down, and each classification. ## Home page rendering ```task id: INFD-WP-0003-T03 status: done priority: high state_hub_task_id: "b0dfae8b-e8f8-5257-b275-8d486a067c6b" ``` When a review is configured and the person is signed in, `GET /` renders the overview grouped as above, with open items first. The manual memo-id form stays below the overview as a fallback. This is server-rendered only: no scripts, the same CSP, all text escaped. Tests: a WSGI test in `tests/test_browser_auth.py` or `test_review_component.py`, plus one Chromium check in `tests/browser_review.mjs` if that harness is cheap to extend. ## Docs and scope ```task id: INFD-WP-0003-T04 status: done priority: medium state_hub_task_id: "6c38b102-943d-5bde-96ac-3e15e2e8e8ab" ``` Update `docs/protected-browser-review.md` and `SCOPE.md` with the overview and the boundary argument above. ## Outcome — 2026-09-21 All four tasks are done. After sign-in, `GET /` shows the grouped overview above the memo identifier form. There are 432 automated tests with actual Approval Engine, Audit Core and Flex Auth, and 13 Chromium checks. There are no actionable residuals. Deployment of the surface stays with `INFD-WP-0001-T08` and the deployment packet. It is not new work from this plan.