1What this is — and what it is not
The Study Lifecycle Monitor (Study_Lifecycle_Monitor.html) is an at-a-glance operational console for a biostatistician watching a portfolio of early-phase studies at the program / operational level. It answers one practical question across all eight studies at once: which studies are slipping on the things biostatistics owns — milestones, data readiness, TLF production, and double-programming — and which one deserves my attention first this week?
Who it is for
The intended user is the biostatistician (or biostatistics lead) coordinating deliverables across multiple concurrent studies. It is built for triage and conversation: open it before a portfolio stand-up, scan the KPI strip and heatmap, click into the one or two studies that are red, and walk in already knowing where the operational pressure is. Every score it shows is computed from operational metadata only and is fully transparent — the exact formulas and thresholds are printed inside the dashboard itself.
What it is — and what it is not
This is the operational / program complement to the participant-safety dashboard, TRIALMON_Dashboard.html. The two cover different worlds and do not overlap:
| Concern | This dashboard (Study Lifecycle Monitor) | TRIALMON (companion) |
|---|---|---|
| Watches | Deliverables, data readiness, TLF production, lifecycle milestones | Participant-safety monitoring |
| Level | Program / operational, study-aggregate | Participant-level clinical signals |
| Question | Are we on track to deliver? | Is anyone at risk? |
Boundaries — read these before you rely on anything here.
- Decision-support, not validated software. The scores are a triage aid to direct attention; humans decide. Nothing here is a regulated output.
- Operations-only — no PHI, no participant-level data, no reported clinical numbers. Only read-only operational metadata (query counts, percent-clean, milestone dates, TLF stage counts) is ever in scope.
- Reported / regulated values come only from validated tools — Phoenix WinNonlin, Pinnacle 21, the EDC/CTMS of record, and the TLF program tracker. This dashboard never sources a number that goes into a deliverable.
- The demo data is SIMULATED. Eight studies (
CP-101…CP-108) are generated from a fixed seed, reproducible run to run. It is a seeded demonstration, not real study data — note theSIMULATED DEMO DATAbadge in the header and footer.
Layout, top to bottom
The page reads as a single top-to-bottom triage flow. A header carries the Biostatistics Operations badge, the SIMULATED DEMO DATA badge, and a study-focus selector that drives every per-study panel. Below it:
- KPI strip — six portfolio counters (active studies, at-risk, on-watch, open queries, average deliverables complete, next DB lock).
- Portfolio health heatmap — a study × dimension RAG matrix (Timeline, Data, TLF, Resource), sorted worst-first; click any cell to drill in.
- Operational early-warning signals — the ranked list of fired alerts, red-first (top nine shown).
- Portfolio trend — an 8-week two-line trend (open queries vs. TLFs finalized) across all studies, each line on its own scale.
- Selected-study panels — milestone track, data readiness, TLF production funnel, and the full-width deliverables pipeline, all driven by the focused study.
- Study roster — a sortable table of all eight studies; click a row for the detail modal.
A per-study detail modal opens from either a heatmap cell or a roster row, and a footer repeats the honesty and governance disclaimer.
How to read color anywhere on the page. Every RAG cell, bar, and pip uses one consistent scale on a 0–100 score: green = on track, amber = watch, red = at risk.
This same banding governs the heatmap cells, the KPI at-risk/on-watch counts, and the per-dimension scores, so once you have it, you can read the whole console.
The portfolio is deliberately seeded so one study, CP-108, is forced into an at-risk Reporting state (DB lock past due, TLF production far behind, milestones overdue). That study becomes the initial focus when the page loads, so you land on a worked at-risk example rather than an empty calm — useful when demonstrating the console or learning its panels.
2Quick start — a 5-minute weekly review
This is the fastest defensible way to read Study_Lifecycle_Monitor.html once a week. The dashboard is decision-support, not autopilot: it ranks where your operational attention should go, but a human decides every action. Work the steps top-to-bottom — each one narrows the portfolio from "all 8 studies" down to "the one I act on first."
The 5-minute loop
#kpis) — 30 seconds. Read the six counters left-to-right for a portfolio pulse. The two that should stop you are colored cells: At risk (count of studies with overall >66; red if any) and On watch (count with overall in 33–66; amber if any). Also note Avg deliverables complete (green if >70, amber if >45, else red) and Next DB lock — it names the nearest study, e.g. Next DB lock (CP-108), turns amber when <14 days out, and shows — if no study has a positive countdown. If "At risk" reads 0 and nothing is amber, you can move faster through the rest.#heat) — 60 seconds. Rows are already sorted by overall risk descending, so the top row is your worst study. Scan the four dimension columns — Timeline, Data, TLF, Resource — and find the red (>66) and amber (33–66) cells. A red cell tells you not just which study but which dimension is driving its risk, so you can triage by failure mode (e.g. a red Data cell = query/cleaning problem; a red TLF cell = output production lag). Note the worst 1–2 studies and the specific red dimension for each.#signals) — 60 seconds. This ranked list turns scores into specific, actionable alerts; red signals sort first and only the top 9 show. Each line gives a severity pip, the study id (who), a title, and a detail message. Map each red signal to its type so you know the action:
- DB lock at risk — open queries with the lock close (e.g. "
N open queries with DBL in D days"); red when <10 days. - Query backlog rising — net query growth >10 over the last 3 weeks (e.g. "
+qd open queries over the last 3 weeks"); red when growth >25. - TLF production behind — finalized fraction below 60% while in Reporting/DB Lock (e.g. "
X% finalized while in Reporting"); red when below 35%. - Double-programming lag — independent-QC programming behind in reporting (always amber).
- Milestone overdue — lists the past-due milestone keys (always red).
#trend): the amber line is portfolio open queries and the blue line cumulative TLFs finalized over 8 weeks — confirms whether things are getting better or worse.#modal) — 90 seconds. Open the per-study detail dialog two ways: click the offending red cell in the heatmap (this focuses the modal on that exact dimension and shows "focus: dim" in the header), or click the study's row in the roster (#tbl, sortable — click a header to re-sort, default is overall risk descending). The modal shows the study header (id — name; design · phase · Lead) and an 8-tile grid: Overall risk with its on-track/watch/at-risk label, the four dimension scores, Enrollment (enrolled/target + sites), Open queries · clean · SDV, Days to DB lock, the TLF cascade (planned→programmed→qcd→finalized), and double-programmed % · discrepancies. Read the tiles that match the red dimension to confirm the root cause. The open "Where these numbers would come from" note ties each metric to its real source — milestones→CTMS, enrollment/queries/clean/SDV→EDC, TLF funnel→TLF program tracker, deliverables→Protocol→CSR register — so you know which validated system to query for the authoritative figure. Close with × or a backdrop click.#data, #funnel, #ms, #deliv) — 60 seconds. Selecting a study (via modal entry point or the header #studySel) re-renders the lower panels for it. Use them to pin down the action: Data readiness for the open-query sparkline and the days-to-DB-lock status line (amber when 0<days<21; otherwise "DB lock not scheduled/reached"); the TLF production funnel for where output is stuck in the planned→programmed→QC→finalized pipeline; the Milestone track for any red (past-due) dots; and the Deliverables pipeline for the lagging phase (Startup/Conduct/Analysis/Reporting). Write down a concrete next step per red study — e.g. "CP-108: DBL overdue, TLF finalized 10% in Reporting → escalate to lead, pull TLF tracker for true counts" — and assign an owner. The dashboard surfaces; you decide and act.What "done" looks like
After the loop you should have: the count of at-risk and on-watch studies, the worst study and its driving dimension, the specific signal(s) behind it, the validated source you'll query for authoritative numbers, and one written action with an owner. In the seeded demo, CP-108 is deliberately forced at risk (Reporting phase, DB lock 24 days overdue, ~10% of TLFs finalized, milestones past due), so it rises to the top row of the heatmap and is the default focus — a good worked example to practice the loop on.
TRIALMON_Dashboard.html, not here. Run both in a weekly review for full coverage.3The data model & the SIMULATED banner
Everything you see in Study_Lifecycle_Monitor.html is generated from a single deterministic seed at page load. There is no server, no file read, and no network call. The portfolio is built once, scored once, and rendered. This section explains exactly what that synthetic portfolio contains, why it looks the way it does, and how each made-up field maps to a real source so you can read the dashboard correctly and brief others without overclaiming.
The SIMULATED banner — three places, one promise
The honesty disclosure is repeated in three locations so it cannot be missed on a screenshot or a printout:
- Header badge — an amber
SIMULATED DEMO DATApill next to the title (alongside theBiostatistics Operationsbadge). - Footer (#foot) — the full disclaimer: self-contained, offline, SIMULATED DEMO DATA (seeded, reproducible) — not real study data; operational monitoring only (no PHI, no participant-level data, no reported clinical numbers; reported values always come from validated tools); transparent operational scoring — no predictive model and no experimental components.
- README — the same statement plus the "Deliberately excluded" list.
The per-study modal repeats a fourth, narrower version of the promise in its provenance note: "Operational fields only — no PHI, no participant-level or reported clinical values."
The seed and the PRNG
The portfolio is driven by a small splitmix-style 32-bit pseudo-random generator. One line creates it and three helpers wrap it:
Because the seed is fixed at 20260621 (the build date, 2026-06-21, read as an integer), every reload produces the identical portfolio: same study list, same scores, same signals, same heatmap. This is what "reproducible" means here — two people on two machines see exactly the same demo. TODAY is likewise frozen to 2026-06-21, so all the day-count math (days-to-DB-lock, overdue milestones) is stable rather than drifting with the wall clock.
rng(20260621) to get a different-but-still-reproducible portfolio, or widen/narrow the genStudy ranges (the ri/rf/pick calls) to change the character of the studies. The seed is the only thing that determines what you see — there is no hidden state.How many studies, and how they are built
The portfolio is exactly 8 studies, generated in a loop (for i in 0..7: genStudy(i)) and given sequential ids CP-101 through CP-108 (101 + i). Each genStudy(i) call returns one canonical study object — the same shape consumed by every panel and by the go-live adapter. The KPI strip's "Active studies" counter is simply STUDIES.length, which is why it reads 8.
The four phases and phase-conditioned realism
Every study sits in one of four lifecycle phases:
The index i spreads studies roughly evenly across phases, with a 30% chance of nudging one phase later — so the eight studies cover the whole protocol-to-CSR span rather than clustering. The point of phase is that it conditions almost every other field, so the demo behaves like a real portfolio instead of uniform noise. The engine first draws a hidden lifecycle-progress fraction prog (0 to 1) from a phase-specific band, and then derives the visible metrics from it:
| Field | How phase shapes it |
|---|---|
prog (hidden progress) | Startup rf(.05,.25); Conduct rf(.3,.6); DB Lock rf(.6,.8); Reporting rf(.8,.98) |
| Enrollment | target = pick([24,32,40,48,60,16]); enrolled = Startup 0–40% of target, Conduct 50–100%, otherwise full |
Open queries (data.openQ) | Startup ri(0,6); Conduct ri(25,120); DB Lock ri(10,48); Reporting ri(0,8) — backlog peaks mid-conduct, drains toward reporting |
Query trend (qtrend) | 8-week back-cast ending at openQ (qtrend[7] = openQ); Reporting phase trends downward (queries closing) |
| Clean % / SDV % | cleanPct = min(.999, prog*0.7 + rf(.2,.32)); sdvPct = min(.999, prog*0.6 + rf(.2,.35)) — later studies are cleaner |
| TLF funnel | planned = pick([90,120,150,180,72]); a reporting proxy by phase drives the programmed → qcd → finalized cascade, so output ramps only as a study approaches reporting |
| Deliverables | per-phase totals {Startup:14, Conduct:26, Analysis:34, Reporting:20} with descending stage weights [1, .85, .55, .2] so later deliverable phases lag earlier ones |
Milestones are likewise derived from prog: a base date of TODAY − (prog*240 + 30) days, offsets [0,18,35,150,185,215,250] for the seven keys (Protocol, SAP, FPFV, LPLV, DBL, TLFs, CSR), each marked done if its date has passed (with 92% reliability), wip if due within the next 14 days, risk if past due and not done, else todo. A study with prog > 0.9 force-completes its first five milestones. daysToDBL is then computed straight from the DBL milestone's date — which is what every "days to DB lock" readout and the DB-lock-pressure scoring term consume.
The deliberately at-risk study: CP-108
A demo of an operational monitor is useless if nothing is ever red. So after the eight studies are generated, the last one — CP-108 (STUDIES[7]) — is deliberately forced into a clearly at-risk state. This is a hard-coded override, not a draw of the RNG:
This profile is a textbook crisis: a study past its DB-lock date, deep into Reporting, with only 10% of TLFs finalized, double-programming behind, and two overdue milestones. It deliberately exercises the red end of several rules at once:
- Heatmap — CP-108's Timeline, TLF, and Resource cells go red, lifting its overall risk above all peers.
- Early-warning signals — it fires "TLF production behind" (10% finalized while in Reporting, red), "Double-programming lag" (42%, amber), and "Milestone overdue" (TLFs, CSR past due, red). Note it does not fire "DB lock at risk": that signal only triggers when
daysToDBLis positive (an upcoming lock), and CP-108's lock date is already in the past (−24). - KPI strip — it is the study counted in "At risk," turning that cell red.
Because the dashboard's initial focus (SEL) is set to the study with the highest overall score after sorting, the forcing also guarantees the app opens focused on CP-108 — every selected-study panel (milestone track, data readiness, TLF funnel, deliverables, modal) lands on the crisis study first, which is exactly what you want a triage tool to do.
What each synthetic field maps to in reality
The fiction is structured so that going live is a field-for-field swap — the synthetic generator and the real-data adapter return the identical study object shape. Each panel already documents its real source (the modal's "Where these numbers would come from" note states it explicitly). The mapping is:
| Demo field | Real source of record |
|---|---|
| id, phase, milestones, enrolled/target, sites | CTMS |
| openQ, qtrend[8], cleanPct, sdvPct, daysToDBL | EDC |
| tlf.planned / programmed / qcd / finalized | TLF program tracker |
| deliv {phase: {done, total}} | Protocol→CSR deliverables register |
| prog.dblProgPct, prog.discrep | TLF tracker / programming metadata |
All of these are read-only operational metadata — counts, percentages, dates, statuses. None of them is a participant-level record or a reportable clinical value, by design. The wiring section walks through loadPortfolio(), the async stub that replaces genStudy with reads from those five sources.
Using the data model in practice
Study_Lifecycle_Monitor.html. Confirm the amber SIMULATED badge is present — if it ever isn't, stop and check what data is loaded before trusting a number.4KPI strip
The KPI strip is the top row of Study_Lifecycle_Monitor.html — six counters that summarize the entire portfolio (all 8 studies, CP-101 through CP-108) in one glance before you read any panel below it. Each counter shows a large value over a small label. Four of the six are color-coded green/amber/red; two are neutral counts. Nothing here is study-specific — the strip ignores the focus selector and always aggregates across the whole portfolio. Read it left to right as a triage: how many studies, how many in trouble, how heavy is the data-cleaning load, how far along is the work, and what is the next hard deadline.
The six counters
| KPI | What it counts / aggregates | How to read it |
|---|---|---|
| Active studies | The portfolio size — STUDIES.length, fixed at 8 in the demo. | Denominator for everything else. Neutral (no color). If you wire a live source, this becomes your live study count. |
| At risk | Number of studies whose overall risk score exceeds 66 (sc.overall > 66). | Red whenever the count is 1 or more; green only when it is 0. A non-zero red here is your first action item — go to the heatmap and find the red rows. |
| On watch | Number of studies in the watch band: overall score above 33 and at or below 66 (33 < sc.overall ≤ 66). | Amber whenever the count is 1 or more; green when 0. These are not emergencies but are trending the wrong way — review before they cross 66. |
| Open queries (portfolio) | Sum of every study's open-query count (Σ s.data.openQ across all 8). | Neutral total — the portfolio-wide data-cleaning backlog. Rising week over week means EDC cleanup is falling behind somewhere; the Portfolio trend panel shows the direction and the roster shows which studies own the queries. |
| Avg deliverables complete | Mean across studies of each study's completion ratio. For each study: (sum of deliv.done) ÷ (sum of deliv.total) over its four phases; that per-study ratio is averaged across all 8 and shown as a rounded percent. | Green if >70%, amber if >45%, red otherwise. This is an unweighted average of ratios, not a portfolio-wide done/total — a small study counts as much as a large one. Treat it as overall program momentum, not a precise completion figure. |
| Next DB lock | The smallest positive days-to-DB-lock across the portfolio, shown as Nd with the owning study id in the label, e.g. Next DB lock (CP-104). | Amber if that value is under 14 days; otherwise neutral. Shows — when no study has a future DB lock. This is your nearest immovable deadline — pair it with the "DB lock at risk" early-warning signal. |
How the risk bands behind two of the counters are defined
"At risk" and "On watch" both key off each study's overall risk score, so the same threshold ladder used everywhere on the dashboard governs these two counters.
Because the bands are mutually exclusive, a study is counted in exactly one of "At risk" or "On watch" (or neither, if green). The two counters never double-count the same study.
CP-108 into the at-risk state (it is a past-due Reporting-phase study), so on first load you will see "At risk" red with a count of 1 — that is expected and exists to exercise the red state and the signals below.Working the strip
5Portfolio RAG heatmap & the scoring model
The #heat panel is the heart of Study_Lifecycle_Monitor.html: a study-by-dimension RAG matrix that compresses every study in the portfolio into four colored scores plus an overall. It is the first place to look each morning and the launch pad for every drill-in. This section explains exactly what each cell means, the arithmetic behind it, and — critically — what the colors do and do not entitle you to conclude.
How to read the matrix
Each row is one study (label = s.id, e.g. CP-104; hover for the full s.name). Rows are sorted by overall risk descending, so the study most in need of attention sits at the top. Each of the four columns is a scored dimension:
- Timeline — milestone slippage and pressure from the approaching database lock.
- Data — open-query burden, data-cleaning completeness, and source-data verification, amplified near DB lock.
- TLF — how far the table/listing/figure pipeline is from finalized, weighted by reporting proximity.
- Resource — independent double-programming progress and open programming discrepancies.
Every cell shows Math.round(s.sc[dim]) — an integer 0–100 — painted by the same RAG rule used everywhere in the dashboard:
(equivalently rag(v) returns 'r' when v>66, 'a' when v>33, else 'g')
Higher is worse: the score is a risk number, not a completion percentage. A green Timeline cell of 8 means little slippage; a red Data cell of 74 means the query/clean/SDV picture is poor with the lock bearing down. The inline collapsible note directly under the heatmap quotes these same thresholds (<33 green / 33–66 watch / >66 at risk) so the model is never hidden from the reader.
The four sub-scores, input by input
Every dimension is built from named operational inputs and then passed through clamp(...), which bounds the result to [0,100]. The exact formulas are reproduced from the dashboard's scoring object below. Two shared multipliers appear repeatedly:
repPressure(s): Reporting = 1 · DB Lock = .6 · Conduct = .25 · else .1
Timeline
Inputs: count of milestones whose status is 'risk' (overdue and not done), plus dblPressure(s).
Each overdue milestone adds 22 points; the DB-lock proximity term contributes up to 45. So a single overdue milestone with a lock more than 60 days out scores 22 + .2×45 ≈ 31 (green), while two overdue milestones at/after the lock date scores 44 + 45 = 89 (red).
Data
Inputs: s.data.openQ, s.data.cleanPct, s.data.sdvPct, and dblPressure(s).
Open queries saturate their 45-point contribution at 120 open queries; incomplete cleaning and incomplete SDV add up to 30 and 25 respectively. The whole bracket is then scaled by lock pressure — the identical data picture reads materially worse in a study days from lock than one in early Conduct.
TLF
Inputs: s.tlf.finalized, s.tlf.planned, repPressure(s).
The fraction not yet finalized drives the raw score; reporting proximity scales it. A study with 10% of TLFs finalized in Reporting (repPressure = 1) scores 90 × 1.1 = 99 (red); the same 10% in Startup (repPressure = .1) scores 90 × 0.38 ≈ 34 (amber) — early studies aren't punished for not having finalized outputs yet.
Resource
Inputs: s.prog.dblProgPct (double-programmed %), s.prog.discrep (open discrepancies), repPressure(s).
Lagging independent (double) programming contributes up to 55 unconditionally; open discrepancies add up to 45 but only matter as reporting nears, via repPressure.
The overall score
The matrix sort key and the KPI/roster risk swatch all come from a single weighted blend of the four dimensions:
Timeline carries the most weight, Data and TLF nearly as much, Resource the least. The same green/amber/red thresholds apply to overall, which is what defines the portfolio counters: At risk = studies with overall > 66, On watch = 33 < overall ≤ 66.
[0,100], overall is itself bounded to [0,100] and reads on the same scale as the cells around it. A row can show a green overall while still carrying one red dimension cell — always scan across the row, not just the rightmost value.Click-to-drill
The heatmap is the primary navigation surface. Clicking any cell does three things at once: it sets SEL to that study, opens the per-study modal (#modal) focused on the clicked dimension (the modal subline shows focus: dim), and re-renders the selected-study panels — Milestone track, Data readiness, TLF funnel, Deliverables pipeline — to that study. So a red Data cell is one click from the open-query sparkline and days-to-DB-lock line that explain it.
Where the inputs come from at go-live
In the demo every input is synthetic, but the data adapter maps each one to a read-only operational source: milestones and phase from CTMS; openQ, qtrend, cleanPct, sdvPct, daysToDBL from the EDC; the TLF funnel counts from the TLF program tracker; deliverables from the Protocol→CSR register; and dblProgPct/discrep from programming metadata. Only operational metadata crosses — no PHI, no participant-level data, no reported clinical values.
rng(20260621)) — useful for learning the panel and exercising the green/amber/red spread, but not real study values. This panel is the operational/program complement to TRIALMON_Dashboard.html, which covers participant-safety monitoring; the Study Lifecycle Monitor deliberately watches deliverables, data readiness, TLF production, and milestones only.6Operational early-warning signals
The Operational early-warning signals panel (#signals) is the dashboard's triage list. It scans all eight studies in the portfolio, fires any signal whose trigger condition is met, then ranks the results red-first and shows the top nine. Each row carries a severity pip (red r or amber a), the study id that owns it (who), a short title (t), and a detail message (m). When nothing crosses threshold you see the empty state: "No operational signals above threshold."
(b.sev==='r')-(a.sev==='r')), then sliced to nine. A short, all-amber list is a good day; a list that is full and red-led is your morning standup agenda.There are exactly five signal types. They are deliberately distinct: a DB-lock signal is about the lock date colliding with open data, a query-backlog signal is about the trend regardless of lock date, the two TLF/programming signals are about output readiness near reporting, and the milestone signal is about a date that has simply passed. A single study can fire several at once — that is informative, not redundant.
The five signals at a glance
| Signal | Trigger | What it means | Action & owner |
|---|---|---|---|
| DB lock at risk | daysToDBL>0 && daysToDBL<21 && openQ>15. Red if daysToDBL<10, else amber. |
The database lock is within three weeks but a meaningful query backlog is still open. Message reads "N open queries with DBL in D days." The lock is jeopardized by data that is not yet clean. | Data management drives query resolution and confirms the cleaning runway; PM decides whether to hold or move the lock date. Biostatistician/lead confirms the SAP-driven analysis can still run on the locked snapshot. Red = escalate today. |
| Query backlog rising | qd = qtrend[7]-qtrend[4] > 10 (net open-query growth over the last 3 weeks). Red if qd>25, else amber. |
The open-query count is trending the wrong way — issues are being raised faster than they are being closed. Message reads "+qd open queries over the last 3 weeks." A worsening data-cleaning trajectory, independent of any lock date. | Data management investigates the source (new edit checks, a problem site, a late data transfer) and rebalances reviewer load. Lead tracks whether the trend reverses week-over-week. Red trend warrants a root-cause check, not just more reviewers. |
| TLF production behind | repPressure(s)>=.6 (phase is Reporting or DB Lock) && finalized/planned < .6. Red if finalized/planned<.35, else amber. |
The study is at or near reporting, yet fewer than 60% of planned TLFs are finalized. Message reads "X% finalized while in <phase>." Output production is lagging given how close the deliverable deadline is. | Biostatistician/lead owns: re-sequence the TLF program, confirm SAP-final shells, and check whether the bottleneck is programming, QC, or sign-off. PM re-checks the CSR timeline. Red here is the strongest output-risk flag near reporting. |
| Double-programming lag | repPressure(s)>=.6 && dblProgPct < 60. Severity amber (fixed). |
Near reporting, independent (double) programming is under 60% complete. Message reads "P% double-programmed, K open discrepancies." The independent-QC arm is behind, so finalized outputs may lack full verification. | Biostatistician/lead reallocates the QC programmer and works the open discrepancy list to zero before sign-off. This is the QC-coverage companion to "TLF production behind" — clear both before declaring any TLF finalized. |
| Milestone overdue | At least one milestone with status risk (past due date, not done). Severity red (fixed). |
One or more of the seven lifecycle milestones (Protocol, SAP, FPFV, LPLV, DBL, TLFs, CSR) is past its due date without completion. Message lists the overdue milestone keys joined by ", " followed by "past due." |
PM owns the milestone timeline and replans; the milestone's natural owner acts (e.g. biostatistician for SAP/TLFs/CSR, data management for DBL, sites/CRA for FPFV/LPLV). Always red — confirm whether the date slipped or the status update is simply stale. |
daysToDBL<10, else amber. Query backlog rising — red if qd>25, else amber. TLF production behind — red if finalized/planned<.35, else amber. Double-programming lag — always amber. Milestone overdue — always red.How the signals relate to the scores
Signals are discrete fired alerts; the heatmap dimension scores are continuous risk levels. They draw on overlapping inputs but answer different questions. A study can carry a high Timeline score (driven by overdue*22 + dblPressure*45) while only the milestone signal has actually fired; conversely a query trend can fire "Query backlog rising" before the Data score crosses 66. Use the signal list to know what to act on now and the heatmap to know which study is heaviest overall.
Working the panel: a triage pass
who study id and the milestone/lock named in the detail message.For participant-safety signals (DLT triggers, lab trajectories, AE patterns), this panel is silent by design — that is the role of the companion TRIALMON_Dashboard.html. The Study Lifecycle Monitor (Study_Lifecycle_Monitor.html) watches deliverables, data readiness, TLF production, and milestones only.
7Milestone track
The Milestone track panel (#ms, with the heading #msTitle) is the selected study's lifecycle timeline. It draws the seven standard milestones in left-to-right order as a row of colored dots, each labelled with its key and its date. The panel title shows the selected study id and its current phase (for example, CP-104 — Conduct). It is driven entirely by the currently selected study (SEL), which you change from the heatmap, the roster, or the header study-focus selector.
The seven milestones, in order
The sequence is fixed (the MS_KEYS list) and is the same for every study. Each step renders its key (m.k) and its date (m.d, formatted YYYY-MM-DD):
- Protocol — protocol finalized/approved. The lifecycle's first gate.
- SAP — Statistical Analysis Plan signed off.
- FPFV — First Participant First Visit (enrollment opens).
- LPLV — Last Participant Last Visit (enrollment/visits complete).
- DBL — Database Lock. This is the pivot milestone: its date also drives
daysToDBL, the data-readiness clock, and the Timeline dimension's lock pressure. - TLFs — Tables, Listings, and Figures finalized.
- CSR — Clinical Study Report. The final lifecycle gate.
How each dot is colored (status)
Every milestone carries a status (m.s) that maps to a dot color class. Read the dots left to right; you should see green giving way to a single blue "you are here" marker, then panel-gray for work still ahead. A red dot anywhere is the thing to act on.
| Status | Dot class | Color | Meaning |
|---|---|---|---|
| done | done | green | Completed — the due date passed and the milestone was met. |
| wip | wip | blue accent | In progress — due within the next 14 days (and not before today). This is the active front of the study. |
| risk | risk | red | Overdue — the due date has passed and the milestone is not done. |
| todo | todo | panel gray | Not yet started — the due date is in the future. |
TODAY = 2026-06-21), evaluated in this order:done if the milestone is completed (due date < TODAY and met);else
wip if the due date falls within the next 14 days (TODAY ≤ d < TODAY+14);else
risk if the due date is past (d < TODAY) and the milestone is not done;else
todo (the due date is still in the future).When lifecycle progress
prog > 0.9, the first five milestones (Protocol → DBL) are forced to done.TODAY − (prog×240 + 30) days) using fixed day-offsets [0, 18, 35, 150, 185, 215, 250] for Protocol → CSR. So the gap from FPFV to LPLV is the longest stretch, and the final three (DBL → TLFs → CSR) cluster near the end — that compression is expected, not a defect.Reading slippage: on-track vs at-risk vs overdue
"On track" is the absence of red plus a clean left-to-right progression: a green run, exactly one blue wip marker at the current front, then gray todo dots. You read slippage from where the red appears and how far right the green has reached:
- A red dot early in the sequence (e.g. SAP or FPFV) means a foundational gate is overdue — everything downstream inherits that delay.
- A red dot at DBL is the most consequential: it means the lock date has passed unmet, which also drives
daysToDBL ≤ 0and pushes the Timeline dimension toward red. - Red at TLFs and/or CSR means reporting deliverables are past due — pair this with the TLF production funnel and deliverables pipeline to see how far behind output really is.
- If a
wip(blue) dot sits to the left of a greendonedot, that is an out-of-order signal worth questioning with the study team.
", " plus " past due" — so the #signals panel and this track always agree on which keys are red. Each overdue milestone also contributes +22 to that study's Timeline dimension score (overdue × 22), which can tip the heatmap cell amber or red.How to use this panel
id — phase.wip dot — that is the current active milestone. Everything green to its left is complete; everything gray to its right is upcoming.wip, open Data readiness (#data) for the daysToDBL clock and open-query load; if TLFs/CSR are red, open the TLF funnel (#funnel) and deliverables pipeline (#deliv).ctmsStudies() — supplying id, phase, and the milestones array (Protocol → CSR, each with its date and status), alongside enrolled/target and sites. The per-study modal's provenance note states the same mapping (Milestones → CTMS).TRIALMON_Dashboard.html covers participant-safety monitoring; Study_Lifecycle_Monitor.html (this dashboard) covers operational/program status only.8Data readiness
The Data readiness panel (#data) summarizes the database-cleaning state of the selected study in four rows: a clean % bar, an SDV % bar, an open-query sparkline with a current count, and a one-line days-to-DB-lock status. Together these answer one operational question: is this database on track to lock clean and on time? Switch the selected study with the header focus select, a heatmap cell, or a roster row.
edcMetrics(s.id)); reported and regulated numbers always come from validated tools (Pinnacle 21, Phoenix WinNonlin, EDC/CTMS), never from this dashboard. The demo data is SIMULATED (seed rng(20260621)).Clean % bar
Clean % (d.cleanPct) is the share of the database judged clean — entered, edit-checked, and free of open issues. It is shown as a filled bar whose width equals the percentage and whose color is inverted: the panel colors the bar by ragColor((1-cleanPct)*100), so the bar is the RAG color of how much is not clean.
pct(cleanPct). Clean bar color = ragColor((1 - cleanPct) * 100) → red when cleanPct < 0.34, amber when 0.34 ≤ cleanPct < 0.67, green when cleanPct ≥ 0.67.Read the color, not just the length: a 60%-clean bar is amber (40% unclean), and only at roughly 67% clean and above does it turn green. The number printed to the right is the raw clean %.
SDV % bar
SDV % (d.sdvPct) is source-data-verification coverage — the share of data verified against source. Same bar idea, but with a stricter color rule: ragColor((1-sdvPct)*120). The ×120 multiplier (vs ×100 for clean) means SDV must be higher than clean % to reach the same color band.
pct(sdvPct). SDV bar color = ragColor((1 - sdvPct) * 120) → red when sdvPct < 0.45, amber when 0.45 ≤ sdvPct < 0.725, green when sdvPct ≥ 0.725.Open-query sparkline and count
The Open queries row shows two things: an 8-week sparkline of d.qtrend and the current count d.openQ. By construction qtrend[7] equals the current openQ, so the rightmost point of the line is today; the line reads oldest (left) → newest (right), one point per week.
(v-mn)/(mx-mn) over the 8 weeks). It shows trend shape, not absolute level — a study with 4 queries and one with 110 queries can produce visually similar lines. Always read the sparkline together with the number beside it: the number gives the level, the line gives the direction.The count turns amber when openQ > 40 (otherwise muted). For interpreting the shape: a line trending down toward the right is a database closing out; a line trending up is a growing backlog. A rising backlog is also caught independently by the Query backlog rising early-warning signal, which fires when the net change over the last three weeks qtrend[7] - qtrend[4] > 10 (red if > 25).
Days to DB lock
The status line reports the gap between today and the DBL milestone (s.daysToDBL, derived from the DBL milestone date). It reads "N days to DB lock" when DBL is in the future, and otherwise "DB lock not scheduled" (Startup) or "DB lock reached" (date passed). It is colored amber only when 0 < daysToDBL < 21 — i.e. lock is within three weeks; otherwise it is muted.
daysToDBL > 0 → "daysToDBL days to DB lock"; else "DB lock not scheduled" (Startup) / "DB lock reached". Amber when 0 < daysToDBL < 21.How the four fields interact
None of these rows is decisive on its own — readiness is the combination of cleaning state and time pressure. The dashboard encodes exactly that interaction in the Data dimension score, which multiplies the cleaning gaps by proximity to lock (dblPressure):
clamp( (min(1, openQ/120)*45 + (1-cleanPct)*30 + (1-sdvPct)*25) * (0.5 + 0.6*dblPressure(s)) ), where dblPressure rises as DBL nears: d≤0→1, d<14→.85, d<30→.6, d<60→.35, else .2 (Startup is a flat .15).Two readings of this formula:
- Same gaps, different timing. A given open-query backlog and unclean fraction count for far more when DBL is days away than when it is months away — the
(0.5 + 0.6*dblPressure)factor roughly doubles the score as lock approaches. A messy database is tolerable early and alarming late. - Worst case: low clean % close to DBL. High
(1-cleanPct)and high(1-sdvPct)multiplied by a near-1dblPressuredrive the Data score toward red, and Data carries 0.28 weight in the overall risk score — so this single situation can push the whole study to At risk.
daysToDBL is between 1 and 20 and openQ > 15 (red if daysToDBL < 10), with the message "N open queries with DBL in D days".TRIALMON_Dashboard.html; this Study_Lifecycle_Monitor.html watches operational readiness only.9TLF production funnel
The TLF production funnel panel (#funnel) shows, for the currently selected study, how its tables, listings, and figures move through production from planning to sign-off. It is a four-stage funnel of horizontal meter bars, each scaled against the number of Planned outputs so you can read attrition between stages at a glance. To populate it for a study, set the header study-focus <select> (#studySel), click a heatmap cell, or click a roster row — all three set SEL and re-render this panel.
The four stages
The funnel walks the standard output-production path. Each meter's width is 100 * value / planned, and the fill is a blue gradient (#2b6cb0 → #4ea8ff):
| Stage | Field | Meaning |
|---|---|---|
| Planned | t.planned | Total TLF shells/outputs scoped for the study (the funnel's 100% reference). Drawn from the SAP and TLF shells. |
| Programmed | t.programmed | Outputs that have a first (production) program written and producing output. |
| QC passed | t.qcd | Outputs that have cleared independent QC (e.g. double-programming reconciliation resolved). |
| Finalized | t.finalized | QC-passed and signed off. The panel note states verbatim: Finalized = QC-passed & signed off. |
Reading a healthy vs. bottlenecked funnel
Because every bar is scaled to planned, a healthy study shows four bars stepping down gently — each stage slightly shorter than the one above it, with Finalized not far behind Programmed. A bottleneck appears as a cliff: one bar is much shorter than the bar immediately above it, marking the stage where work is piling up.
- Many Programmed but few QC-passed (Programmed bar long, QC passed bar abruptly short): a QC bottleneck. Production is outrunning independent QC capacity — outputs are written but not getting reconciled/verified.
- QC-passed but few Finalized (QC passed long, Finalized short): a sign-off bottleneck. Verified outputs are waiting on review/approval, not on programming.
- Planned but little Programmed (only the top bar is long): production has not really started — expected early in a study, a concern late in one.
#studySel, or click into it from the heatmap/roster).#signals) and the per-study modal for the matching alerts (below) to confirm whether the lag is flagged given the study's phase.How the funnel drives the TLF risk dimension and signals
The funnel's counts feed the TLF heatmap dimension. The score is weighted by reporting proximity, so the same finalized fraction is benign early and serious late:
repPressure: Reporting = 1, DB Lock = .6, Conduct = .25, else .1
rag(v): green ≤ 33, amber (watch) 33 < v ≤ 66, red (at risk) v > 66; clamp bounds to [0,100]
Two early-warning signals fire directly off funnel-related counts, and only when the study is near reporting (repPressure(s) ≥ .6, i.e. phase is Reporting or DB Lock):
Red if finalized/planned < .35, else amber. Message: "X% finalized while in <phase>".
Severity amber (fixed). Message: "P% double-programmed, K open discrepancies".
prog.dblProgPct (double-programmed %) and prog.discrep (open discrepancies) belong to the Resource dimension, so a QC bottleneck in the funnel often shows up as elevated Resource and TLF scores together in the heatmap row.Worked reference: the forced at-risk study
The demo deliberately forces CP-108 into an at-risk reporting state, which makes its funnel the textbook QC/sign-off bottleneck. Its counts are programmed = 0.45 × planned, qcd = 0.22 × planned, finalized = 0.10 × planned, with dblProgPct = 42 and phase = Reporting. Read top-to-bottom, the bars fall 100 → 45 → 22 → 10: production already lags, QC roughly halves what was programmed, and almost nothing is signed off — while the study is in Reporting. Because finalized/planned = 0.10 < .35 with repPressure = 1, the "TLF production behind" signal fires red, and dblProgPct = 42 < 60 fires the amber "Double-programming lag" signal. This is the pattern to recognize: a steep cliff at the QC stage on a study that is out of runway.
Upstream production assets
The funnel is the monitoring view; the outputs themselves come from the standardized TLF program template libraries that supply the production code for each shell — the SAS TLF pseudocode/template library and the parallel R (pharmaverse) TLF template library. Those libraries are organized per design (parallel, crossover, single-sequence, SAD, MAD) and are the assets that move counts from Planned into Programmed; the dashboard simply tallies their progress through QC and sign-off via the TLF program tracker.
planned / programmed / qcd / finalized from the TLF program tracker as read-only operational metadata only; no PHI, no participant-level data, and no reported clinical values cross into the dashboard. For the participant-safety counterpart, see TRIALMON_Dashboard.html; this panel lives in Study_Lifecycle_Monitor.html and is operational/program monitoring only.10Deliverables pipeline by phase
The Deliverables pipeline panel (#deliv) is the dashboard's program-management lens: for the selected study it shows how many deliverables are done versus total in each of four lifecycle phases. It is a scaled echo of the Protocol-to-CSR deliverables register, so reading it well means reading the shape of the whole study lifecycle, not just a single bar. This section also covers the two portfolio-level readouts that aggregate deliverables across all eight studies: the Avg deliverables complete KPI and the Portfolio trend, plus how to find the crunch points.
What the panel shows
The card is full-width and holds one bar per phase, in lifecycle order. The four phase keys (s.deliv) are fixed:
- Startup — Protocol, SAP, CRF/eCRF design, randomization spec, analysis-dataset specs and the early planning deliverables.
- Conduct — deliverables produced while the study is enrolling and running: data-management plan execution, interim/DSMB outputs, ongoing programming specs.
- Analysis — the analysis-stage deliverables: ADaM datasets, the bulk of the TLF program, derivations and define documentation.
- Reporting — the closeout deliverables: final TLFs, statistical report inputs and CSR contributions.
For each phase the bar is rendered as follows:
Note the color polarity: the RAG color is driven by the incomplete fraction. A phase that is mostly finished (high done/total) yields a small (1 − ratio)×90 value and reads green; a phase that is barely started reads red. The ×90 factor means a phase has to be almost untouched (roughly under 27% complete) before it tips red, and below about 63% complete before it goes amber — phases that are well underway stay green.
How to read it phase-by-phase
The synthetic generator deliberately lags later phases behind earlier ones: each phase's completion is pulled down by its position in the lifecycle (an increasing per-phase lag term plus a stage-weight divisor and small noise), so Startup tracks closest to the study's overall progress while Reporting trails furthest. The expected, healthy picture for a study still in its early-to-middle life is therefore a left-to-right downward staircase: Startup fullest, Reporting emptiest. That is normal and not by itself a problem.
#ms) and the study's phase shown in #msTitle to decide whether a low bar is a concern.Per-phase deliverable counts (register scale)
The four phases are sized from a fixed register so the demo mirrors the 136-item Protocol→CSR register at scale. Totals per phase are fixed:
| Phase | Register total (per study) | Stage weight | Typical completeness as study matures |
|---|---|---|---|
| Startup | 14 | 1.00 | Fills first; usually green by Conduct |
| Conduct | 26 | 0.85 | Climbs through the conduct phase |
| Analysis | 34 | 0.55 | Largest bucket; green only near/after DB lock |
| Reporting | 20 | 0.20 | Fills last; expected red until Reporting phase |
The done count for each phase is min(total, round(total × clamp₀₁(prog / weight − index×0.15 + noise))), where prog is the study's overall lifecycle progress (0..1), index is the phase position (Startup 0 → Reporting 3), clamp₀₁ bounds the completion fraction to [0, 1], and noise = rf(−0.05, 0.05). The combination of the divisor and the increasing index×0.15 lag term is what pushes later phases down relative to prog. Because Analysis is the largest bucket (34) and sits mid-lifecycle, it is usually the phase that signals the analysis-readiness squeeze before DB lock — watch it climb as prog rises.
Reading overall portfolio progress
Two readouts roll deliverables up to the whole portfolio.
Avg deliverables complete (KPI strip, #kpis) is the headline number:
This averages each study's overall deliverable completion (summing done and total across all four phases first, then taking the ratio), then averages those eight study-level percentages. Because it pools all phases, a portfolio dominated by early-phase studies will read lower even when every individual study is on track — interpret it together with the phase mix in the roster, not as a standalone grade.
Portfolio trend (#trend) plots the cumulative TLFs finalized line (blue, #4ea8ff) alongside the open-queries line (amber, #e6b450) across 8 weeks. The deliverables register itself is not trended week-by-week; the finalized-TLF line is the closest proxy for reporting-deliverable velocity. The legend shows current values q[7] and f[7] (newest week).
f[w] = Σ round(finalized × (0.35 + 0.65·w/7)) across the 8 weeks. It illustrates direction of travel for the demo only. With real data wired in (see go-live), this would be replaced by the actual finalized-TLF time series from the TLF program tracker. Do not read week-over-week TLF deltas as a measured rate in the demo.Finding the crunch points
A crunch point is a study whose remaining deliverable load is concentrated in a phase that is due now. Use this workflow:
#tbl), sorted by Risk descending (default). The riskiest studies float to the top.#ms) for any risk (red) milestone dots — TLFs and CSR milestones flag overdue reporting deliverables directly.#signals): a TLF production behind signal (fires when phase is Reporting or DB Lock and finalized/planned < 0.6) corroborates an empty Reporting bar near the lock/report date.How this ties to scoring
The deliverables panel is descriptive — it is not a direct input to the four risk dimensions. The TLF and Resource dimensions are driven by the TLF program tracker and programming metadata (finalized/planned, double-programmed %, open discrepancies), not by the register counts. So the deliverables bars give you the program-management context behind a study's risk score without double-counting it. When a study scores red on Timeline or TLF, the deliverables pipeline tells you which lifecycle phase is carrying the unfinished work.
Where the numbers come from
In the demo every deliverable count is SIMULATED, generated deterministically from the seed rng(20260621) and reproducible run to run. At go-live the panel is fed read-only by the Protocol→CSR deliverables register via deliverablesRegister(s.id), returning {phase: {done, total}} for Startup / Conduct / Analysis / Reporting; only operational metadata crosses — no participant-level data.
For participant-safety signals — clinical and laboratory monitoring at the participant level — use the companion TRIALMON_Dashboard.html. This Study Lifecycle Monitor (Study_Lifecycle_Monitor.html) is the operational/program complement: it watches deliverables, data readiness, TLF production and milestones, not participant-level clinical signals.
11Study roster & the drill-down modal
The Study roster (#tbl) and the per-study detail modal (#modal / #modalBox) are the bottom of the funnel: the heatmap and signal panels tell you which study and which dimension deserves attention, the roster lets you triage all eight studies in one sortable table, and the modal gives you the full per-study picture before you act. This section covers how to sort and triage the roster, exactly what the modal shows, and the recommended drill-down path from a colored cell or fired signal to a defensible operational decision.
The roster table: columns and what each one tells you
The roster lists all eight studies (CP-101 through CP-108) with nine columns. It opens sorted by overall risk descending (sortKey='overall', sortDir=-1), so the most at-risk study sits at the top on load — in the demo that is the deliberately forced at-risk study CP-108.
| Column | Field | How to read it |
|---|---|---|
| Study | s.id | The study identifier (CP-101…CP-108). Click anywhere in the row to open the modal. |
| Phase | s.phase | One of Startup, Conduct, DB Lock, Reporting. Drives the reporting/DBL pressure weights in scoring. |
| Design | s.design | The study design label. |
| Lead | s.owner | The responsible owner — your first call when a row is red. |
| Enrolled | enrolled/target | Recruitment progress against target. |
| Open Q | s.data.openQ | Open EDC queries. Cell turns amber when openQ > 40. |
| Clean | s.data.cleanPct | Percent of data clean. |
| TLF final | finalized/planned | Finalized TLFs against planned — the headline output-production ratio. |
| Risk | s.sc.overall | RAG swatch (rag(overall)) plus the rounded overall score. The triage column. |
Sorting and triage
Click any column header to sort by that column; clicking the same header again toggles the direction (if(sortKey===k) sortDir*=-1; else { sortKey=k; sortDir=-1; }). Use the columns as a triage lens rather than reading rows top-to-bottom:
- Risk (default) — start here. Reds first, ordered worst-to-best, gives you the portfolio's escalation queue in one glance.
- Open Q — sort descending to find the studies driving the portfolio query backlog; amber cells (>40) jump out.
- TLF final — sort ascending to surface reporting-phase studies whose output production is lagging.
- Phase — group Reporting and DB Lock studies together, since those are where TLF and double-programming pressure bite hardest.
- Lead — group by owner when you are preparing a per-lead status conversation.
rag(v) returns 'g' (green, on track) when v ≤ 33, 'a' (amber, watch) when 33 < v ≤ 66, and 'r' (red, at risk) when v > 66.Opening the modal: entry points
The same modal opens from two places, and the entry point changes what the header tells you:
- From a roster row — click any row. The modal opens on that study with no dimension focus.
- From a heatmap cell — click a cell. This sets
SELto that study, re-renders the selected-study panels (milestones, data readiness, TLF funnel, deliverables), and opens the modal with a focus dimension noted in the header subline (e.g.focus: Data), telling you which column's color sent you there.
You can also set the selected study from the #studySel dropdown in the header bar, which re-renders all selected-study panels but does not open the modal.
What the modal shows for a single study
The modal (#modalBox) has three parts: a header, an eight-tile key-value grid, and a provenance note.
Header. id — name on the top line; a subline reading design · phase · Lead owner, with · focus: dim appended if you arrived from a heatmap cell.
Eight KV tiles — the full operational snapshot in one view:
| Tile | Shows |
|---|---|
| Overall risk | Rounded overall score plus its label (on track / watch / at risk). |
| Timeline / Data | The two dimension scores side by side. |
| TLF / Resource | The other two dimension scores. |
| Enrollment | enrolled/target plus number of sites. |
| Open queries · clean · SDV | EDC data-readiness trio in one tile. |
| Days to DB lock | daysToDBL (negative means the planned lock date has passed). |
| TLF cascade | planned → programmed → qcd → finalized counts. |
| Double-programmed % · discrepancies | prog.dblProgPct and prog.discrep — the independent-QC programming status. |
Provenance note ("Where these numbers would come from") is always open and maps each block to its real source: milestones → CTMS; enrollment, queries, clean, SDV → EDC; the TLF funnel → the TLF program tracker; deliverables → the Protocol→CSR register.
Close the modal with the × button or by clicking the backdrop.
Recommended drill-down workflow
SEL on the study, re-renders the selected-study panels, and opens the modal with the focus: dim note so you know which dimension drove the color.TRIALMON_Dashboard.html. When a row here looks operationally fine but you need the clinical-safety view, that is the dashboard to open instead.12Portfolio trend panel
The Portfolio trend panel (#trend) is the only panel that shows direction of travel for the whole portfolio rather than a single snapshot. Where the KPI strip and heatmap tell you where you are right now, this panel tells you which way the portfolio is moving over the last 8 weeks. It plots two lines on a single SVG canvas: portfolio-wide open queries (amber) and cumulative TLFs finalized (blue). You read it to answer one question fast: is the operational load building or draining?
What the two lines are
- Open queries (amber,
#e6b450) — for each weekw,q[w]is the sum across all 8 studies of that study's weekly query level (s.data.qtrend[w]). This is a real back-cast series: each study carries an 8-week query trend ending at its current open-query count (qtrend[7] = openQ), and the panel sums them week-by-week. Down is good — the portfolio is closing more queries than it opens. - TLFs finalized (blue,
#4ea8ff) —f[w]is a cumulative count of finalized TLFs across studies. Up is good — output is being produced and signed off.
The TLF line is not a stored historical series. Per spec, f[w] = sum over studies of Math.round(s.tlf.finalized*(0.35+0.65*w/(W-1))) — a synthetic ramp anchored to each study's current finalized count and smeared backward over 8 weeks. It always rises monotonically by construction, so the TLF line's shape is illustrative, not measured. Trust its endpoint (f[7] = today's portfolio finalized total, shown in the legend as "TLFs finalized (cumulative): now N") and read its rise as "output exists," but do not interpret week-to-week TLF slope as a real production cadence. The open-query (amber) line is the honest direction signal; weight your reading toward it.
How to read direction and momentum
Two independent scales: each line is normalized to its own maximum within the canvas (viewBox 0 0 1000 150, pad 26). The lines are not on a shared y-axis, so do not compare their heights to each other — never read "the lines crossed" as meaningful. Read each line only against its own earlier points. Points are plotted left (oldest) to right (newest), one per week. The legend prints the two current values, q[7] and f[7].
Momentum (amber): compare the last 3 weeks, q[7] − q[4]. This is the exact quantity the "Query backlog rising" signal fires on (>10 amber, >25 red).
q[7] − q[4] echoes the per-study "Query backlog rising" trigger in the signals panel.f[7] in the legend is low relative to total planned TLFs, output is thin regardless of slope — corroborate against the per-study TLF funnel (#funnel) and the "TLF production behind" signal.q[7] should equal the "Open queries (portfolio)" KPI (both are sum of s.data.openQ). If your eye and the KPI disagree, trust the KPI number.Reading the four shapes
| Amber (queries) | Blue (TLFs) | What it means | What to do |
|---|---|---|---|
| Falling | Rising | Healthy portfolio: cleaning is winning and output is flowing. | Routine review. Spot-check the at-risk study still trends right. |
| Flat | Rising | Net-zero queries: opened ≈ closed. Cleaning is treading water. | Investigate which studies are stalling — flat at portfolio level can hide one study surging while another drains. Drill via the heatmap Data column. |
| Rising | Rising | Wrong-direction queries: backlog building even as TLFs finalize. Often a Conduct-phase study ramping enrollment. | Find the contributor(s). Check the "Query backlog rising" signal for the study id and the +N magnitude. |
| Rising | Flat / low endpoint | Worst pattern near a lock: load building, output not moving. | Escalate. Pair with "DB lock at risk" and "TLF production behind" signals; open the per-study modal. |
Flat is not neutral. A flat amber line means new queries are arriving as fast as old ones close — steady-state churn, not resolution. In an early-phase portfolio you usually want the amber line trending down as studies move from Conduct toward DB Lock. A persistently flat portfolio line, or one that's flat only because a draining study masks a climbing one, is a prompt to leave the portfolio view and use the heatmap (#heat) Data column to find the per-study story.
What a wrong-direction or flat trend should prompt
This panel does not name the culprit study — it is portfolio-summed. When the amber line rises or refuses to fall, treat it as a pointer into the rest of the dashboard:
- Go to the signals panel (
#signals). A rising portfolio query line almost always corresponds to one or more "Query backlog rising" signals, each tagged with a study id (who) and the net growth over the last 3 weeks. Red there meansq[7]−q[4] > 25for that study. - Open the heatmap Data cells. Sort is by overall risk; scan the Data column for amber/red. Click a cell to open the per-study modal focused on Data.
- In the modal, read the open-query sparkline and days-to-DB-lock line. A backlog rising into a near DB lock is the "DB lock at risk" condition (
daysToDBL>0 && <21 && openQ>15). - If the blue line is flat/low near reporting, check "TLF production behind" and "Double-programming lag" signals and the per-study TLF funnel.
The open-query and finalized counts shown here are operational metadata only — counts of queries and document sign-offs, never PHI, never participant-level clinical data, never a reported clinical result. Any regulated or reported number comes only from validated tools (EDC/CTMS for queries and milestones, the TLF program tracker for finalized counts, and Phoenix WinNonlin / Pinnacle 21 for analysis outputs) — never from this trend line. The trend is decision-support to tell you where to look; a human decides what it means.
Demo-data caveat. In the shipped Study_Lifecycle_Monitor.html the series are SIMULATED and seeded (rng(20260621), reproducible). The forced at-risk study CP-108 contributes a deliberately ugly profile (finalized at ~10% of planned, DBL already past). At go-live the same lines are fed read-only from EDC (edcMetrics(s.id) supplies openQ and the real qtrend[8]) and the TLF program tracker (tlfTrackerCounts(s.id)) — at which point you can replace the synthetic TLF ramp with a true finalized-by-week series and read its slope as real cadence. This is not validated software; it complements TRIALMON_Dashboard.html, which watches participant-safety signals rather than operational throughput.
13Wiring it to live data
Out of the box, Study_Lifecycle_Monitor.html is fully self-contained: it generates all eight studies (CP-101 through CP-108) from a seeded pseudo-random generator, rng(20260621), so every reviewer sees the identical green/amber/red spread. Every number on the screen is SIMULATED DEMO DATA. This section explains the single seam where you swap that synthetic generator for your real operational systems — the DATA ADAPTER — and documents exactly which read-only source feeds each panel and field.
The one seam: loadPortfolio()
The whole dashboard reads from one array, STUDIES. In demo mode that array is built by calling genStudy(i) eight times. The DATA ADAPTER comment block holds an async stub, loadPortfolio(), whose only job is to return that same array of study objects — same field names, same shape — but populated from your live systems instead of the generator. Go-live is a one-line swap:
Because every panel already reads the canonical study-object shape that genStudy returns, you do not touch any panel code. You only implement the four source readers and the merge function inside loadPortfolio().
Four read-only sources, one merge
The adapter pulls from four operational systems and merges their fields into the demo's field names. Each reader is keyed by study id so the dashboard stays organized per study:
ctmsStudies()— CTMS: returnsid,phase, the sevenmilestones(Protocol..CSR with dates and status),enrolled/target, andsites.edcMetrics(s.id)— EDC: returnsopenQ,qtrend[8],cleanPct,sdvPct,daysToDBL.tlfTrackerCounts(s.id)— TLF program tracker: returnsplanned,programmed,qcd,finalized.deliverablesRegister(s.id)— Protocol→CSR deliverables register: returns{phase:{done,total}}for Startup/Conduct/Analysis/Reporting.
A small merge helper, mapToModel(e, t, d), folds the EDC, TLF, and deliverables payloads onto the CTMS skeleton and produces the canonical study object the panels expect.
loadPortfolio() parses. Read-only is the contract: the dashboard observes operational metadata and never writes back to CTMS, EDC, the tracker, or the register.Which source feeds each panel
This is the authoritative mapping. Build your readers to deliver exactly these fields and every panel lights up correctly.
| Panel | Source | Fields |
|---|---|---|
| Milestone track + Portfolio health (Timeline dimension) | CTMS | id, phase, milestones (Protocol..CSR with dates/status), enrolled/target, sites |
| Data readiness + Data dimension | EDC | openQ, qtrend[8], cleanPct, sdvPct, daysToDBL |
| TLF production funnel + TLF dimension | TLF program tracker | planned, programmed, qcd, finalized |
| Deliverables pipeline | Protocol→CSR deliverables register | {phase:{done,total}} for Startup / Conduct / Analysis / Reporting |
| Resource dimension | TLF tracker / programming metadata | prog.dblProgPct (double-programmed %), prog.discrep (open discrepancies) |
What must NOT cross the seam
The adapter carries operational metadata only. The fields above are counts, percentages, dates, and statuses — never the underlying clinical record.
Implementation steps
ctmsStudies() to return one record per active study with id, phase, the seven dated milestones, enrolled/target, and sites. This is the skeleton everything else attaches to.edcMetrics(id), tlfTrackerCounts(id), and deliverablesRegister(id) as per-study read-only pulls returning only the aggregate fields in the table above.qtrend is an 8-element series whose last element equals current openQ (qtrend[7] = openQ), so the open-query sparkline and the "Query backlog rising" signal read correctly.loadPortfolio(), loop the studies and call mapToModel(e, t, d) to merge each source payload into the canonical field names.STUDIES = await loadPortfolio(). Leave every panel untouched.Sanity checks after wiring
- The KPI strip reconciles to your sources: Open queries (portfolio) equals the sum of each study's EDC
openQ; Active studies equals your live study count. - The TLF funnel never shows a later stage exceeding an earlier one — confirm
finalized ≤ qcd ≤ programmed ≤ plannedcoming out of the tracker. - The Timeline dimension responds to real milestone status: any milestone past its date and not done should surface a red dot on the milestone track and fire the "Milestone overdue" signal.
daysToDBLderives from the live DBL milestone date, so the "DB lock at risk" signal and the Next-DB-lock KPI both move with CTMS.
TRIALMON_Dashboard.html: it watches deliverables, data readiness, TLF production, and milestones — not participant-level clinical signals. Participant-safety monitoring lives in TRIALMON. Keep that boundary when you wire sources: clinical signals belong there, operational metadata belongs here.14Governance, guardrails & the two-dashboard split
This dashboard (Study_Lifecycle_Monitor.html) is built around a small set of non-negotiable guardrails. They are not decoration: they decide what the tool is allowed to show, where its numbers may come from, who is allowed to act on them, and why it sits in its own lane rather than overlapping the participant-safety dashboard. Read this section before you put any output in front of a lead, a sponsor, or an inspector.
The five non-negotiables
- Operations-only. The dashboard watches deliverables, data readiness, TLF production, milestones, and programming throughput. It never ingests PHI, never holds participant-level rows (no
USUBJID/SUBJIDrecords), and never displays reported or regulated clinical values. - Reported numbers come only from validated tools. Any number that lands in a CSR, a TLF, or a submission is produced and signed off in a validated environment (for example Phoenix WinNonlin for NCA/PK, Pinnacle 21 for conformance, the EDC/CTMS of record). This dashboard restates operational metadata about those deliverables — counts, percentages, dates — never the regulated results themselves.
- Transparent scoring — no black box. Every risk score is a published arithmetic formula with stated thresholds. The exact dimension formulas and the RAG cut-points are printed inside the dashboard itself (the collapsible note under the heatmap) and in the README. There is no predictive model and no learned weighting to audit.
- Humans decide. The tool ranks, flags, and routes attention. It does not approve a database lock, accept a query backlog, or sign off a TLF. Every signal is a prompt for a person to look, not an action.
- Simulated demo data, clearly labeled. The shipped portfolio is seeded synthetic data, badged
SIMULATED DEMO DATAin the header, footer, and README, and reproducible from the fixed seed. None of it is real study data.
Not validated software. The Study Lifecycle Monitor is decision-support, not a validated system. Do not treat any figure on it as the source of truth for a regulated deliverable, and do not cite it in a submission. When an operational number matters, confirm it against the system of record (CTMS, EDC, the TLF program tracker, and the relevant validated tools) before acting.
What "operations-only" rules out
The boundary is concrete. The following never cross into this dashboard, even via the live data adapter:
- PHI or any directly or indirectly identifying participant information.
- Participant-level records of any kind (one row per participant, per visit, or per event).
- Reported clinical numbers — efficacy estimates, PK parameters, safety incidences, anything that would appear in a TLF or CSR result.
- Unblinded treatment information.
What does cross is read-only operational metadata: study phase, milestone dates and statuses, enrolled/target counts, site counts, open-query counts and their weekly trend, clean and SDV percentages, days to DB lock, TLF stage counts, deliverable done/total tallies, and double-programming percentage with open-discrepancy count. These are program-management facts about the conduct of the work, not clinical observations from it.
A simple test for whether a field belongs here: if removing every participant from the study would leave the number undefined, it does not belong (that is participant-level data). An open-query count belongs; the content of any query does not. A TLF finalized count belongs; the values inside the TLF do not.
Transparent scoring: the formulas are on the wall
Because there is no model to trust, the scoring must be legible. Each study carries four dimension scores plus a weighted overall, all clamped to [0,100]. The collapsible note under the heatmap quotes them; they are reproduced here so you can reconcile any cell by hand.
Timeline = clamp( overdue×22 + dblPressure(s)×45 )
overdue = count of milestones with status risk; dblPressure: Startup = .15; otherwise by days-to-DB-lock d: d≤0 → 1, d<14 → .85, d<30 → .6, d<60 → .35, else .2
Data = clamp( ( min(1, openQ/120)×45 + (1−cleanPct)×30 + (1−sdvPct)×25 ) × (0.5 + 0.6×dblPressure(s)) )
TLF = clamp( (1 − finalized/planned)×100 × (0.3 + 0.8×repPressure(s)) )
repPressure: Reporting = 1, DB Lock = .6, Conduct = .25, else .1
Resource = clamp( (1 − dblProgPct/100)×55 + min(1, discrep/18)×45×repPressure(s) )
Overall = clamp( 0.30×Timeline + 0.28×Data + 0.27×TLF + 0.15×Resource )
RAG thresholds — rag(v): green if v≤33, amber (watch) if 33<v≤66, red (at risk) if v>66. Equivalently rag returns r when v>66, a when v>33, else g. clamp bounds every score to [0,100].
Two consequences are worth internalizing as a user. First, the overall weighting leans on Timeline and Data (0.30 + 0.28 = 58% of the score), so a study can turn red on schedule and data pressure even with TLF and Resource quiet — that is intended for a program lens. Second, both the Data and TLF dimensions are amplified by phase pressure, so the same raw open-query count or finalized fraction scores higher as a study approaches DB lock or enters Reporting. When a score moves and the raw inputs did not, check whether the study changed phase or its days-to-DB-lock crossed a pressure band.
The deliberate two-dashboard split
This is a conscious separation of concerns, not a gap. There are two dashboards and they do not overlap:
| Dashboard | Watches | Does not watch |
|---|---|---|
Study_Lifecycle_Monitor.html (this one) | Deliverables, data readiness, TLF production, milestones, programming throughput — the operational/program lifecycle | Anything participant-level or clinical |
TRIALMON_Dashboard.html (companion) | Participant-safety monitoring | Program/operational deliverables |
The README states the relationship plainly: this Study Lifecycle Monitor is the operational/program complement to TRIALMON. If you are asking "is the work on track to be delivered, locked, and reported?" you are on the right dashboard. If you are asking "is a participant or the population showing a safety signal?" that question belongs to TRIALMON, and nothing here is designed or governed to answer it.
Do not use operational health as a proxy for participant safety. A study can be green across all four operational dimensions and still have a safety concern that only TRIALMON would surface, and the reverse holds as well. Keeping the two lenses separate is what keeps each one honest and within its governed data boundary.
Deliberately excluded
The README lists what was kept out by design, and the footer repeats the core of it. This is standard, defensible operational monitoring only:
- No predictive model and no experimental engine of any kind.
- No research-work-in-progress or manuscript-specific methods — none of the author's personal-research constructs are present anywhere in this tool.
- No participant-level data, no PHI, no reported clinical numbers.
The footer states it for the record: self-contained, offline · SIMULATED DEMO DATA (seeded, reproducible) — not real study data. Operational monitoring only: no PHI, no participant-level data, no reported clinical numbers; reported values always come from validated tools. Transparent operational scoring — no predictive model and no experimental components.
Going live without breaking the guardrails
When the synthetic generator is replaced by real feeds, the governance posture must survive the swap. Follow this sequence.
1. Implement loadPortfolio() to return the exact same study-object shape the generator produces, sourced read-only from the systems of record (CTMS, EDC, the TLF program tracker, the Protocol→CSR deliverables register) via REST or a nightly CSV export.
2. Map only operational metadata into the model — the per-field source list in the data adapter documents exactly which system feeds each field. Confirm no PHI, no participant-level row, and no reported clinical value is in the payload.
3. Remove the SIMULATED DEMO DATA badging only once live data is confirmed wired and validated against the source systems; until then, leave every honesty label in place.
4. Keep the scoring formulas visible. If weights or thresholds are ever tuned, update the on-screen collapsible note and the README in the same change, so the displayed math always equals the executed math.
5. Re-verify after any change: the embedded JS should pass node --check, and a headless render should produce no NaN and a full green/amber/red spread, exactly as the demo build is verified.
Even live, the rule does not move: reported and regulated numbers stay with the validated tools and the systems of record (for example Phoenix WinNonlin, Pinnacle 21, the EDC/CTMS of record). The dashboard's job is to point a person at the right study and the right deliverable fast — the person, working in the validated system, makes the call.