Study Management — target acceptance criteria tracker¶
This is the single running record of what the programme must deliver and how far it has got.
It exists so that shipping thin slices early (the programme's delivery rule) never loses sight of
the target. Every wave PR updates the rows it delivers, with a link to the evidence (spec,
test name, PR, or staging capture). A row is Met only with evidence; Partial names what is
missing; Deferred names the follow-up that owns it.
Delivery rule (recorded 2026-09-02): favour feature delivery, then iterate. The rule governs how
review findings are triaged: a finding holds a PR only when it shows a regression, data-loss or
corruption risk, or a security problem; every other finding is recorded as a follow-up and the PR
ships. It does not waive the plan's CI and merge gates — focused tests, a current generated client,
lint/build/docs validation, every review thread resolved or explicitly deferred, no failed or
in-progress required check, and the final user review — which still apply to every PR. For
flag-gated slices the controlled staging proof is attached before the flag is enabled anywhere
(C7.2), not before each merge of dormant code; unflagged corrections attach preview or test evidence
to their own PR.
Scope change (recorded 2026-09-02): the Risk of Bias feature is disabled and its development is
on ice, so the Risk of Bias family is omitted from Waves 2–5. Rows that mention it are marked
Out of scope until product revives the feature. Its server-side revision field from Wave 1B
remains as dormant backend code.
Status legend: Not started · In progress (PR #) · Met (evidence) · Partial (gap) ·
Deferred (follow-up) · Out of scope (reason).
A. Programme target (the MVP the user must be able to do)¶
ID
Criterion
Source
Status
A1
An authorised user launches a Bulk Study Update from the Library and finds the same operation in Processing after navigation or refresh
README MVP
Not started (Waves 3 + 5)
A2
Every operation shows the exact raw status, truthful progress, bounded errors, initiator only when the server can prove it, and valid created/updated/completed timestamps with no year-one defaults
README MVP; D7–D9, D13
Partial — contract truth met by PR #3052/#3053 (year-one fix, truthful counts, initiator projection); UI rows Wave 2B, pages Waves 3–5
A3
Library, Searches and Processing link to each other and back to the owning context consistently
README MVP; D1, D3
Not started (Waves 3–5)
A4
The experience works at 320 CSS px, at 200–400% zoom, with keyboard and screen reader
README MVP; D16, D17
Not started (Waves 3–5)
A5
State stays stable during loading, reconnecting, partial failure, completion and live updates; stale HTTP/SignalR payloads never regress newer state
README MVP; plan Wave 2
In progress — server revisions met (PR #3052/#3053); client rejection Wave 2A
A6
Users find things intuitively placed and easy to navigate (product owner's UX mandate, 2026-09-01)
design-decision.md
Not started — verified per UI wave by the staging walkthrough and final review
B. Cross-cutting design contract (applies to every UI wave)¶
ID
Criterion
Source
Status
B1
Three linked routes under one "Study management" navigation group; compact navigation uses PR #2994's adaptive primitive
D1
Not started (Wave 5)
B2
Processing is read-only history; only Bulk PDF exposes cancel/retry; no other family ever renders cancel/retry
D2
Not started (Wave 5) — no cancel/retry API exists for other families (verified)
B3
Contextual summaries on Library/Searches with "View in Processing"; the deep link reveals the operation even when terminal and outside the default filter, with notice + Clear + focus
D3, D17
Not started (Waves 3–5)
B4
Processing default filter = Active + Needs attention; "All operations" pages 25 rows with honest remaining count
D4
Not started (Wave 5)
B5
One shared status-chip component on the Bulk PDF StatusView contract (ok/stopped/warn/muted/info, honest bar modes, ariaValueText)
D5
Not started (Wave 2B)
B6
Deployed labels reused verbatim; Bulk Study Update sentence-cased enum with raw enum + value in row detail
D6, D14
Not started (Wave 2B presenter)
B7
Unknown status renders "Unknown status (n)", never Running
D7
Not started (Wave 2B) — Bulk PDF's "Status unavailable" reconciliation is O5/Wave 4
B8
Honest progress only: determinate bars need a real numerator/denominator; completion reports matched/modified, and a 0-changed run says so
D8
Partial — resultSummary contract met (PR #3052); presentation Wave 2B
B9
Missing data renders "Not available", never fabricated
D9
Partial — nullable timestamps met (PR #3052); presentation Wave 2B/3
B10
Processing grouping Needs attention → Active → Completed with counts; fixed column grid; contained horizontal scrollers
D10, D11
Not started (Wave 5)
B11
Live updates re-sort deferred while a row is expanded; reconnecting keeps rows visible and marks them stale
D12
Not started (Wave 5)
B12
Bounded error lists (first 10 of N, Show all)
D13
Not started (Wave 5; strips in 3–4)
B13
Server-filtered aggregate with per-family view gates; route visibility decided by PermissionReport capabilities, never by emptiness
D15; README decision 2
Partial — server gates in PR #3053 (merging); client guard Wave 5
B16
Accessibility contract on every page: one polite live region per page, role="status" notices, aria-expanded on expandable rows, labelled focusable scroll regions, progressbar aria-valuetext, reduced-motion static indeterminate track
D16
Not started (each UI wave proves its own surface)
B17
Security/product approval of the permission matrix is recorded before the flag is enabled in any environment (exposure gate; server proof from PR #3053 is evidence, not the approval)
README plan gate
Not started — blocks C7.4, never a wave PR
B14
Theme tokens: --syrf-warning-container, --syrf-warning-accent, --syrf-info-container exist and are the only new tokens; no existing --syrf-* redefined. Feature components consume only emitted --mat-sys-* / --syrf-* tokens per design-token-mapping.md: no hard-coded hex colours, no Bootstrap or private Material variables, no new fonts, and no breakpoint system competing with the shared responsive contract
design-decision.md; design-token-mapping.md
Met for the tokens (PR #3059 merged 945fa86a4); consumption restrictions checked per UI wave
B15
Feature exposure gated by generated default-off studyManagementProcessing flag with runtime-catalog entry
Snapshot membership reconciled by project audit.version; omitted-job race test proves a late HTTP payload cannot delete a newer SignalR-created row
Not started (Wave 2A)
C2.3
ProjectDetails per-family id arrays reconciled the same way
Not started (Wave 2A)
C2.4
Pure adapters for Search Import, Bulk Study Update, Bulk PDF: every enum value, unknown branch, invalid dates → null, no invented data, warnings separate from errors
processing and canonical searches routes; the legacy admin/systematic-searches URL keeps working via a compatibility redirect with a routing test; Study management navigation group; flag-off direct URL and navigation absence
Not started
C5.2
Guard and visibility by PermissionReport capabilities for every permission combination
Not started
C5.3
Default filter, reset, result count; 250-row fixture filter/sort/Show more
Not started
C5.4
Deep-link reveal of a completed referenced operation with notice, Clear and focus
Not started
C5.5
Grouped list, deferred resort while expanded, bounded error lists, row detail with raw enum + value, full UTC timestamps (created/updated/completed, "Not available" when null) alongside any relative time, initiator, and copyable job ID
Not started
C5.6
One loading boundary; empty state reads "none visible to you" with links to Library and Searches; load failure states "Your operations are unaffected" with a Retry action; reconnecting keeps rows visible and marked stale; stable focus during SignalR updates (D15, D12)
Not started
C5.7
Mobile/zoom reflow; screen-reader names and result-count announcement; colour-independent meaning; forced-colors block; app-shell skip link
Not started
C5.8
Processing describes itself as the history the server retains (Bulk PDF keeps 20 per search / 100 per project; other families per their retention) and never implies nothing was pruned; payload size/retention recorded with the 250-row fixture; paged history API follow-up created if needed
O5 — unknown-status fallback alignment with Bulk PDF
Wave 4
Background sweep for long-expired UploadingToS3 Bulk Update jobs
Separate backend PR (PR #3052 follow-up)
CLAUDE.md pointer to this feature and the delivery rule above
After PR #2900 releases the file (single-writer rule)
Paged history API
Only if the 250-row measurement in Wave 5 shows the aggregate is not acceptable
SearchController.CalculateRob authorization gap (PR #3060, drafted, CI green)
Parked by product 2026-09-02 while RoB is on ice. Note: robToolEnabled=false only hides the UI; the endpoint stays callable by any authenticated user. Product owner to decide whether to merge #3060 as a security fix regardless of the UI freeze