Strengthening the Contributor Pipeline: A Proposal

First, a sincere thank-you to the maintainers and to OpenCoreEMR. The amount of work going into this project – infrastructure, code, and the unglamorous maintenance that keeps a system this large running – is enormous, and it’s easy to take for granted. I’m raising the following as a contributor who wants OpenEMR to thrive, and I think we share that goal.

I also want to say up front: I’m not against testing. This is medical records software. Regressions can affect patient safety and data integrity, and a strong test suite is exactly the kind of thing a serious EMR should have. So this isn’t “testing bad.” It’s a question about balance and support, and about how we treat contributions from outside the core group.

Analysis of PR History

I pulled together some public data from our own GitHub (the figures below span roughly the past year). A few patterns stood out:

· We lean very heavily on a small number of contributors.

Across merged PRs, just three accounts ‚Äî two OpenCoreEMR developers plus Dependabot ‚Äî account for roughly three-quarters of the total, and OCE’s contributors are close to half of all human-authored merges. That’s a testament to how much OCE carries day to day. It’s also a real dependency for a project this important, and worth being clear-eyed about.

· Community PRs face noticeably more friction.

They’re closed without merging about three times as often as OCE’s (~15% vs ~5%), and the ones that do land wait far longer – the slowest tenth sit over a week and a half, versus around three days for OCE’s. (To be fair, “closed without merging” includes PRs people abandoned or superseded themselves – but a higher abandonment rate is itself a friction signal.)

· When community PRs don’t make it, it’s usually the automated checks & not the idea.

The large majority die on a failing check rather than a “we don’t want this,” and a striking share fail only on mechanical things we already ship auto-fixers for – code style/Rector, PR-title format, whitespace. The most common hard failure is our static-analysis gate at its strictest setting, which full-time engineers clear routinely and occasional contributors often don’t.

· The open queue is mostly community work that isn’t moving.

Of ~169 open PRs right now, about 98 are from community contributors versus ~55 from maintainers/OCE, and the median open PR has been waiting roughly four months – some far longer. Two concrete examples: a small, self-contained patient-finder improvement ([#8865]( Patient Finder Update by psoas · Pull Request #8865 · openemr/openemr · GitHub )) has been open since last September with no review at all, and a larger calendar-template migration opened last June has drawn only limited human review across a year of activity.

· Merging of community PRs now runs almost entirely through one maintainer.

In recent months a single person has handled most community merges – on the order of 90% – while the rest with write access have barely touched that queue. That’s an unsustainable amount to put on one person, and it’s a big part of why outside PRs back up: there’s essentially one pair of hands on the gate.

· Feature work can sit while under-the-hood changes move ahead.

Bug fixes and new features sometimes get deprioritized behind infrastructure and testing work – even though features are what the practices using OpenEMR notice. (This one is my impression rather than something I measured.)

To be fair about what the data does not show: this isn’t a case of every outside PR being ignored. Community PRs that catch a maintainer’s attention do get discussion, and several active contributors merge at healthy rates. The problem is more specific, and it shows up in two distinct ways. The PRs that get closed without merging mostly fail on an automated check rather than on the merits. And the PRs that don’t get closed often just sit – sometimes for many months with no human review at all, like the two above.

Either way, the bottleneck isn’t the quality of the idea; it’s how few hands are free to pick these PRs up and help them over the line.

That’s a sustainability question as much as a fairness one.

Two Suggestions

Pair a high bar with help clearing it.

The data above suggests many community PRs are lost not to bad ideas but to the automated checks – formatting, title format, static-analysis strictness – that a maintainer or a bot could clear in seconds.

If we’re going to ask contributors to meet a demanding standard, it’s worth making sure we also help them meet it: auto-applying our own fixers, pointing people to the exact failing check, and pairing on the harder ones.

A high bar plus little guidance ends up working as a filter rather than a quality gate.

Apply the standard consistently.

It strengthens everyone’s trust in the process when the same expectations apply to maintainers and to first-time contributors alike – including the expectation that what gets merged is green and complete.

I’d rather not single out specific PRs here, but I think we’d all agree the rules feel fairer when they’re applied evenly.

A Concrete Proposal

I’d like to suggest a small, bounded process change:

1. Reserve ~15 minutes of each admin meeting for PR triage.

Walk the community PR queue, assign a reviewer to each open PR, and agree on a rough timeframe. Right now community merging falls to essentially one person; spreading it across those of us with write access would lighten that load and keep PRs from stalling.

2. Write down admin responsibilities toward outside contributions.

A short, explicit statement that facilitating non-maintainer contributions is part of the role. It’s a real time commitment, but naming it makes it real.

3. Auto-fix the mechanical checks.

A lot of community PRs fail only on things we already have fixers for – code style/Rector, PR-title format, whitespace. Letting a bot apply those (or push the fix) on incoming PRs would reclaim good contributions at zero cost to standards.

4. Tier the strictest static-analysis gate.

Keep the toughest level in core `src/`, but consider easing it for new clinical/interface code, so the single hardest check isn’t the first wall a feature contributor hits.

This isn’t lowering standards in core – just not making the strictest gate the universal entry barrier.

5. Help on the harder failures instead of just bouncing them.

Aim for a human response on community PRs within a few days, and for solid feature PRs that stall on test coverage, pair a reviewer to help get the tests over the line.

We do want tests on clinical code – we can help people get there.

6. Track a couple of numbers.

Open-PR count and median age by author group, plus community-vs-OCE merge and rejection rates. They’re easy to pull from GitHub, and they tell us whether any of this actually helped.

The Upside

A healthier contributor pipeline means more features practices can use, less load concentrated on a handful of people, and a project that isn’t so dependent on any single contributor or company.

The testing investment we’ve made is an asset – I just want to make sure it’s matched by an equal investment in the people trying to contribute, and that good outside work doesn’t sit for months.

I’d love to hear how others see this, especially the admins – whether the 15-minute triage idea seems workable, and what I might be missing about constraints on your side.

1 Like

Thanks for putting real numbers behind this, David. I re-pulled the public PR data myself and your core read holds. My summary:

  • The bus-factor risk is real and it’s the thing to fix. I merge ~94% of community PRs; when my time gets redirected, the queue stalls. The durable fix is to distribute the load, not to find one backup.
  • Most of my effort goes to raising the scaling factor, not reviewing one PR at a time — release cadence, automating mechanical checks, and paying down structural debt. That’s deliberate: there’s no scale in one-at-a-time review.
  • We should act on three of your six proposals (#1, #3, #5) and push back on one.
  • One correction to the diagnosis: when community PRs don’t land, the data points to reviewer attention, not the automated checks.

Supporting detail below; skip to “Proposals” if you just want the actions.

The data

Your headline numbers check out, a couple understated:

  • Concentration. Three accounts (two of us plus Dependabot) are ~71% of merged PRs — a real bus-factor risk.
  • Community PRs face more friction. Once decided, community PRs are closed-without-merge ~30% of the time vs ~5% for write-access holders; the slowest tenth take ~a month vs a few days.
  • The review-ready queue is mostly stalled community work. Setting aside drafts (~67 of the open PRs are WIP, not up for review), ~100 PRs await review — ~78 community vs ~13 maintainer — median review-ready community age ~104 days. #8865 is a fair example.
  • Merging runs through one person. Of community PRs merged in the last three months, I merged ~94%.

The concentration risk is sharper than “what if he’s on vacation”: I’m paid by OCE, so my time follows company priorities — a single point of failure that can be redirected, not just absent. And it can’t be fixed with one backup, since everyone else with write access is a volunteer. To be clear, OCE’s investment is a net positive — it funds my time and several other paid contributors, and a lot of recent progress traces to that. The risk is the concentration, not the funding. The only durable fix is to spread the load.

Why the “under-the-hood” work comes first

You flagged feature-deprioritization as an impression; part of it is real and deliberate, so here’s the reasoning:

  • Structural debt. The PHPStan baseline suppresses ~144,000 known issues. The PHPStan/Rector/test work exists to stop new contributions from growing that pile, which is why contributors hit the static-analysis wall — they’re landing on a baseline that takes years to clear.
  • Grow at the edges. Fastest way to shrink the legacy core is to stop expanding it: FHIR/REST API first, module second, core only when there’s no other place. I’ve written that ordering down as openemr/openemr#12437 so it lands in CONTRIBUTING instead of living in our heads.
  • Release cadence. In my whole time on OpenEMR we’ve shipped two and a half releases (7.0.4, 8.0.0, 8.1.0 in progress). Fixes only reach users when a release ships, so cadence caps everything else. Automating the release process raises the scaling factor for every future review and security fix — which one-at-a-time review can’t.
  • Invisible security load. 83 published advisories, dozens in the past year, each carrying triage, a private fork, coordinated disclosure, backports, and re-review — almost none of it visible as a public PR, all of it from the same reviewer pool.

On the common read that the automated checks reject good community work: the data says otherwise. Those checks landed in the same ~14-month window that full-time effort ramped up; if they were the problem, rejection would have risen. Instead it fell — closed-without-merge ~46%→~30%, median time-to-merge ~8d→~2.5d. The bottleneck is hands on the gate, not the gate.

Proposals

  • #1 — 15-min triage block. Yes; I’d like to try it at the next admin meeting and will bring the open-community list pre-built. This is the thing that breaks the single-gate problem.
  • #3 — auto-fix mechanical checks. Strong yes. Style/Rector/whitespace/title failures shouldn’t kill a good patch when we ship the fixers. I’ll look into a bot that applies them on incoming PRs.
  • #6 — track numbers. Yes, and publish them — a shared dashboard (open-PR count and median age by author group, merge/rejection rates), not an analysis on my laptop. OpenEMR should also, IMO, publish its telemetry data, so we know what features matter to active users.
  • #5 — response SLA + coverage pairing. Agreed in spirit, less in practicality; the real constraint is reviewer-hours, which is why #1 and load-distribution matter more than a paper SLA.
  • #4 — tier the static-analysis gate for clinical code — I’d push back. This is the surface where a type error is most likely to corrupt data or mask a regression. The fix for contributor pain is your own #5 (help people clear the bar) plus #3 (painless mechanical checks), not lowering the bar where stakes are highest. Open to a narrower version if you have one.

The clearest problem in the data — one person merging the overwhelming majority of community PRs — is exactly what #1 fixes, and the one I most want help with. Thanks for raising this constructively.