diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index b66c7cde7..2dc22d994 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -481,7 +481,7 @@ list, then open the Pending row to confirm the cutoff corpus.
unavailable, so that run is Failed rather than a fabricated score.
The home list is clickable: `GET /api/analysis-runs/{id}` fills a
labeled detail (cutoff, requested date, 12-character digest prefixes
-with full digests on hover, counts, status history)
+that disclose the full digest on activation, counts, status history)
without exposing a DSN or raw record. Opening a cutoff title warns
that the live body may have changed after the run. Status history is detail-only
and uses lookup labels plus occurrence times; a failure event keeps
diff --git a/CHANGELOG.d/0.86.3-analysis-run-digest-disclosure.md b/CHANGELOG.d/0.86.3-analysis-run-digest-disclosure.md
new file mode 100644
index 000000000..f2427d30c
--- /dev/null
+++ b/CHANGELOG.d/0.86.3-analysis-run-digest-disclosure.md
@@ -0,0 +1,5 @@
+# 0.86.3 Analysis-run digest disclosure
+
+Activate a prefix on the run detail to read the full digest. The
+closed panel stays in the document with `hidden`. Hover is not the
+only verification path. The list stays aggregates-only.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 13aeb02f9..a72ba611b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,20 @@ All notable changes to this project are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.86.3] - 2026-08-16
+
+### Fixed
+
+- Analysis-run digest prefixes are disclosure buttons. Open the Demo
+ Corp lineage run, activate `Code` or `Config`, and match the revealed
+ digest to the API payload. The closed panel stays in the document
+ with `hidden` so `aria-controls` has a target, and each prefix meets
+ the 24px pointer target (WCAG 2.2 SC 1.4.13 and 2.5.8; WAI-ARIA APG
+ Disclosure). A hover `title` is no longer the only path. The home
+ list still hides digests even when the list JSON includes them.
+ Requesting a lineage reconstruction now keeps the pending next action
+ on that opened detail: reconstruction has not started yet.
+
## [0.86.2] - 2026-08-16
### Fixed
diff --git a/CLAUDE.md b/CLAUDE.md
index a11127584..764d03fe2 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -3,7 +3,7 @@
Tool-specific pointer. Policy lives in [AGENTS.md](AGENTS.md) and the
ADRs under `docs/adr/`. Do not fork those rules here.
-## Analysis-run seed (v0.85.0)
+## Analysis-run seed (v0.86.3)
`make seed` writes a Demo Corp lineage run and a TEPP run on the same
snapshot (ADR 0013). The TEPP path goes through `tepp_client`. A missing
@@ -15,7 +15,7 @@ theta or a local psychometric substitute. The home list caption stays
transport. A failed lineage row retries reconstruction -- it does not
mention TEPP. A failed period-report row rebuilds the report. A
pending TEPP row does not claim a calibrated measurement.
-Digest prefixes stay audible; hover a prefix to read the full digest.
+Digest prefixes stay audible; activate a prefix to read the full digest.
Opening a cutoff title shows the live post -- compare it with the
cutoff before treating the body as reconstructed evidence (ADR 0016).
`POST /api/analysis-runs` records Pending on an authorized
diff --git a/docs/adr/0016-analysis-run-knowledge-cutoff-posts.md b/docs/adr/0016-analysis-run-knowledge-cutoff-posts.md
index 089443374..60b4d838b 100644
--- a/docs/adr/0016-analysis-run-knowledge-cutoff-posts.md
+++ b/docs/adr/0016-analysis-run-knowledge-cutoff-posts.md
@@ -31,9 +31,13 @@ as reconstructed evidence.
Reproducibility digests on the same detail use a labeled group whose
accessible name does not replace the visible prefixes (W3C Accessible
-Name and Description Computation 1.1). Full digests stay on `title`
-for hover verification and on the API payload; the home list stays
-aggregates-only.
+Name and Description Computation 1.1). Each prefix is a disclosure
+button (WAI-ARIA APG Disclosure; WCAG 2.2 Success Criterion 1.4.13).
+The full digest stays in the document with `hidden` until activation
+so `aria-controls` has a target and keyboard and assistive technology
+can verify it the same way a pointer can. Each prefix button meets the
+WCAG 2.2 SC 2.5.8 24px minimum target. The home list stays
+aggregates-only; the API payload still carries the full values.
Seed and API fixtures backdate in-cutoff posts. A late own-corp private
post remains on the live post list and stays out of the January 2026
@@ -46,8 +50,8 @@ run.
post (2026-02-10) does not appear.
- Open the run, read the live-body warning, then open a listed post
and compare it with the cutoff date.
-- Hover a digest prefix to read the full code or configuration digest
- when you need to match the API payload.
+- Activate a digest prefix (Enter, Space, or click) to read the full
+ code or configuration digest when you need to match the API payload.
- Post-body versioning at the cutoff remains future work.
- Thread-group *run list* visibility now uses the same cutoff
(ADR 0018). A later public post cannot surface a previously hidden
@@ -65,3 +69,10 @@ Recommendation). https://www.w3.org/TR/owl-time/
World Wide Web Consortium. (2018). *Accessible name and description
computation 1.1* (W3C Recommendation).
https://www.w3.org/TR/accname-1.1/
+
+World Wide Web Consortium. (2024). *Web content accessibility guidelines
+(WCAG) 2.2* (W3C Recommendation). https://www.w3.org/TR/WCAG22/
+
+World Wide Web Consortium. (n.d.). *Disclosure (show/hide) pattern*.
+ARIA Authoring Practices Guide.
+https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/
diff --git a/docs/doctoring/ANALYSIS_RUN_REGISTRY_REFERENCES.md b/docs/doctoring/ANALYSIS_RUN_REGISTRY_REFERENCES.md
index b41b31c17..a95dc4362 100644
--- a/docs/doctoring/ANALYSIS_RUN_REGISTRY_REFERENCES.md
+++ b/docs/doctoring/ANALYSIS_RUN_REGISTRY_REFERENCES.md
@@ -9,7 +9,10 @@
|---|---|---|
| W3C PROV-DM and PROV-O | Preserve identifiable entities, activities, agents, generation/use, and derivation without flattening provenance into display-only edges. | `analysis_source_snapshot`, `analysis_run`, authenticated requester, append-only status events, immutable digests; later product bindings continue to use the separate `provenance_*` layer from ADR 0011. |
| W3C Time Ontology in OWL | Keep temporal concepts explicit and avoid collapsing distinct clocks. | Evidence availability and snapshot capture remain on `analysis_source_snapshot`; analysis knowledge cutoff and request time remain on `analysis_run`; status occurrence and database record time remain distinct. `GET /api/analysis-runs/{id}` visible posts apply `created_at <= knowledge_cutoff` (ADR 0016). Opening a listed title warns that the live body may have changed after that cutoff. |
-| W3C Accessible Name and Description Computation 1.1 | Do not let `aria-label` replace visible text the operator must hear. | Analysis-run digest prefixes live in a labeled group; the prefixes remain the accessible contents and the full digest is on `title` for hover verification. |
+| W3C Accessible Name and Description Computation 1.1 | Do not let `aria-label` replace visible text the operator must hear. | Analysis-run digest prefixes live in a labeled group; the prefixes remain the accessible contents of disclosure buttons. |
+| WCAG 2.2 Success Criterion 1.4.13 | Additional content that appears only on hover or focus must not be the only way to complete a task. | Full digests are hidden until the operator activates a prefix button (Enter, Space, or click). Native `title` tooltips are not the verification path. |
+| WCAG 2.2 Success Criterion 2.5.8 | Pointer targets must be at least 24 by 24 CSS pixels. | Each digest prefix button uses `--lw-target-min: 24px` and an inline 24px floor. |
+| WAI-ARIA APG Disclosure | Use a button with `aria-expanded` to show and hide the controlled digest. | `AnalysisRunReproducibilityDigests` keeps the closed `
+ {anyOpen
+ ? analysisRunDigestRevealedNextAction()
+ : analysisRunDigestNextAction()}
+
+ {codeRevisionSha ? (
+
-
- Hover a prefix to read the full digest for verification.{" "}
-
- {codeRevisionSha ? (
- {`Code ${analysisRunDigestPrefix(codeRevisionSha)}`}
- ) : null}
- {codeRevisionSha && configurationSha256 ? " · " : null}
- {configurationSha256 ? (
-
- {`Config ${analysisRunDigestPrefix(configurationSha256)}`}
-
- ) : null}
- ` panel in the document with `hidden` so `aria-controls` always has a target. |
| ISO 8601-1:2019 | Use unambiguous timestamp representation and timezone-aware persistence. | PostgreSQL `timestamptz` for availability, capture, cutoff, request, occurrence, and record clocks; tests use explicit `Z` offsets. |
| PostgreSQL 18 constraints and trigger contracts | Put integrity close to durable truth and use constraints for row shape while triggers enforce cross-row state and serialization. | Digest/check constraints, category allowlists, account-scoped uniqueness, shape constraints, immutable-row triggers, shared snapshot-row locking, and serialized status transitions. |
| NIST SP 800-92 | Treat audit records as bounded, protected operational evidence rather than unstructured application logging. | Append-only status events, machine failure codes, actor identity, occurrence/record clocks, fail-closed rollback, and exclusion of raw source/provider payloads. |
@@ -104,3 +107,10 @@ computation 1.1* (W3C Recommendation). https://www.w3.org/TR/accname-1.1/
World Wide Web Consortium. (2022). *Time ontology in OWL* (W3C Recommendation).
https://www.w3.org/TR/owl-time/
+
+World Wide Web Consortium. (2024). *Web content accessibility guidelines
+(WCAG) 2.2* (W3C Recommendation). https://www.w3.org/TR/WCAG22/
+
+World Wide Web Consortium. (n.d.). *Disclosure (show/hide) pattern*.
+ARIA Authoring Practices Guide.
+https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/
diff --git a/docs/goals/analysis-run-operator-loop.md b/docs/goals/analysis-run-operator-loop.md
new file mode 100644
index 000000000..14b864923
--- /dev/null
+++ b/docs/goals/analysis-run-operator-loop.md
@@ -0,0 +1,34 @@
+# Goal — analysis-run operator loop
+
+**Status:** Active
+**Date:** 2026-08-16
+
+## Goal
+
+A buyer can open a seeded analysis run, hear the digest prefixes, reveal
+the full digests without a pointer, and compare any opened live post
+with that run's cutoff before treating the body as reconstructed
+evidence.
+
+## Current loop
+
+1. #127 is on `feat/role-responsibility-agent-ontology` (`44912a6`).
+ Prefixes are audible; the live-body warning is present.
+2. Land #155 (v0.86.3) so keyboard and AT operators can match a digest
+ to the API payload. Closed panels stay in the document with `hidden`;
+ each prefix is a 24px target. Prefer #155 over #139 `cf8c2e8` and
+ over #135. Do not self-approve or merge from this automation.
+3. Write-clock landing is #150. Prefer it over #131. Do not open a
+ second write-clock PR. Kind-specific pending copy is #149 — do not
+ open a second pending-copy PR. Retention purge + Storybook tokens
+ landing is #154. Prefer it over #145/#134/#137.
+4. #125 (`POST /api/analysis-runs`) is on the same base. Do not open a
+ second create PR.
+5. Post-body versioning at the cutoff remains later work (ADR 0016).
+
+## Out of this loop
+
+Retention purge and the Storybook runner belong to the approved
+frontend-toolchain PR. Failed-run next-action copy already landed with
+#124. Embedded `data:image` rendering landed as 0.86.1. R&R catalog-id
+walks landed as 0.86.2 (#141).
diff --git a/docs/storybook-inventory.md b/docs/storybook-inventory.md
new file mode 100644
index 000000000..09169104d
--- /dev/null
+++ b/docs/storybook-inventory.md
@@ -0,0 +1,22 @@
+# Storybook inventory
+
+Repeating web objects that must stay tokenized and independently
+composable. The Storybook runner itself lands with the approved
+frontend toolchain PR; this inventory is the product list those
+stories must cover.
+
+| Object | Tokens | Next action the story must teach |
+|---|---|---|
+| Analysis-run digest disclosure | `--lw-opacity-meta`, `--lw-font-size-meta`, `--lw-space-digest-gap`, `--lw-font-family-mono`, `--lw-focus-ring`, `--lw-focus-offset`, `--lw-target-min` | Activate a prefix, then match the revealed digest to the API payload. |
+| Analysis-run live-post warning | `--lw-opacity-meta`, `--lw-font-size-meta` | Compare the opened body with the run cutoff before treating it as reconstructed evidence. |
+| Embedded post image | `--post-body-gap`, `--post-image-padding`, `--post-image-border`, `--post-image-radius`, `--post-image-bg` | Read the picture in document order, then run Extract or Ask if you need the OCR text. |
+| Meta caption (`.post-meta`) | `--lw-opacity-meta`, `--lw-font-size-meta` | Read the clock or count, then take the control beside it. |
+
+## References
+
+World Wide Web Consortium. (2024). *Web content accessibility guidelines
+(WCAG) 2.2* (W3C Recommendation). https://www.w3.org/TR/WCAG22/
+
+World Wide Web Consortium. (n.d.). *Disclosure (show/hide) pattern*.
+ARIA Authoring Practices Guide.
+https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/
diff --git a/frontend/package.json b/frontend/package.json
index fb52f7948..b5209226e 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
- "version": "0.86.2",
+ "version": "0.86.3",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/AnalysisRunReproducibilityDigests.test.tsx b/frontend/src/AnalysisRunReproducibilityDigests.test.tsx
new file mode 100644
index 000000000..04e8ff355
--- /dev/null
+++ b/frontend/src/AnalysisRunReproducibilityDigests.test.tsx
@@ -0,0 +1,105 @@
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it } from "vitest";
+import { ANALYSIS_RUN_DIGEST_TARGET_MIN_PX } from "./analysisRunDigests";
+import { AnalysisRunReproducibilityDigests } from "./AnalysisRunReproducibilityDigests";
+
+const CODE_REVISION_SHA = "abcdef0123456789deadbeefcafebabe";
+const CONFIGURATION_SHA256 =
+ "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
+
+describe("AnalysisRunReproducibilityDigests", () => {
+ it("renders nothing when the run has no digests", () => {
+ const { container } = render(
+ {digest}
+
+
+ );
+}
+
+/**
+ * Labeled group of analysis-run reproducibility digests.
+ *
+ * Prefixes remain the accessible contents of the group. Full digests
+ * stay off the home list and stay `hidden` on the detail until the
+ * operator activates a prefix.
+ */
+export function AnalysisRunReproducibilityDigests({
+ codeRevisionSha,
+ configurationSha256,
+}: {
+ codeRevisionSha?: string;
+ configurationSha256?: string;
+}) {
+ const id = useId();
+ const [openCode, setOpenCode] = useState(false);
+ const [openConfig, setOpenConfig] = useState(false);
+ if (!codeRevisionSha && !configurationSha256) {
+ return null;
+ }
+ const anyOpen =
+ (Boolean(codeRevisionSha) && openCode) ||
+ (Boolean(configurationSha256) && openConfig);
+ return (
+
{analysisRunNextAction(selected)}
+ )}