Evidence Base
Counted from the claims in the prose below, not authored — it cannot drift from what the document says.
A well-engineered open-source commerce framework that has quietly lost its steward for the second time in ten years — and a competitor that came back from the dead with a business model behind it.
Three quarters of this report rests on things read directly out of the repository, the git history and public financial records. That is a strong base for questions of fact. The evidence windows: the original sweep ran 18–25 July 2026, one Core Team member answered questions on 3 August, and the load-bearing claims were re-checked against the live system on 8 August for this revision.
Start Here
This section exists so the rest of the report makes sense without prior knowledge of Solidus. If you already know the project and the players, skip straight to Policies & Operations — the decided layer comes first, and the timeline right after it carries the story.
What Solidus actually is
Solidus is not a hosted store you sign up for, like Shopify. It is a set of Ruby on Rails libraries you install into your own application — you run the servers, you own the database, you write the customizations. In Ruby these libraries are distributed as "gems," and Solidus ships about eight of them.
The ones that matter for this report:
solidus_core— the commerce domain: orders, products, payments, shipping, taxes.solidus_backend— the original admin interface. Built in the older Rails style with jQuery. Still the one in use.solidus_admin— the new admin interface, started in 2023 to replace the old one. Still unfinished. Much of this report is about why.solidus— a "meta-gem": a package that installs nothing itself and simply lists which of the others you get by default. Which gems it names is effectively the project's official position on what is ready. Watch this one.
Solidus is not a hosted store: it is a set of Rails libraries you install into your own application — you run the servers, you own the database, you keep every customization.
Who's involved
- Nebulab — Italian e-commerce consultancy, ~27 people. Named in the governance document as the project's Director, a role covering business and organizational direction. Took over stewardship in 2018 and remains a top-tier funder. Their engineering contribution has collapsed to almost nothing since 2024 — a central thread of this report.
- Super Good Software — Canadian consultancy led by Jared Norman. Now the largest contributor of code and joint-largest funder. Healthy and active.
- Stembolt — The agency that created Solidus in 2015 by forking Spree. Acquired by JUUL Labs in 2018 and stopped work. The first steward to walk away.
- Spree · Vendo — Spree is the project Solidus was forked from — abandoned in 2015, revived commercially, now the main competitor. Vendo is the company that sells its paid Enterprise Edition.
- Open Source Collective — A US non-profit "fiscal host." Solidus is not a legal entity and holds no money of its own; OSC legally holds the donations and pays approved expenses.
- The merchants — Mid-market online stores: direct-to-consumer brands, auto parts retailers, book sellers. Most arrived through one of the agencies, and many funded the project directly.
How to read the notation
Every factual claim carries a tag showing where it came from. This is the core discipline of the framework — it stops confident-sounding guesses from passing as findings.
| observed | Seen directly in the system — code read in the repository, a command run, git history, an API response. |
| web | Verified against an external source — a vendor's own site, a release listing, press coverage. |
| stakeholder | Stated by a stakeholder — someone from the project answering directly. Authoritative for business facts, but revisable; re-confirmed when load-bearing. |
| inferred | Reasoned from evidence. Plausible, not established. Do not act on it as fact. |
| assumed | Neither checked nor verified. Everything tagged this way is listed in §22What I Could Not Establish. |
This is a living report written against ESF v0.7, an engineering-strategy framework whose rules are cited where they bind; "rev N" means the Nth numbered revision of this document, and the Decision Log records what each one changed. Until rev 24 there was no stakeholder tag anywhere in this report, because no one from the project had spoken. The courtesy window — the draft was posted in the project's Slack before wider publication, inviting correction — changed that: one Core Team member answered there in two replies an hour apart (rev 24 and rev 25), covering two of the three ranked questions this report had posed, and every stakeholder-tagged claim traces to that exchange. One answer set is corroboration, not access — the remaining limits are discussed honestly in §22What I Could Not Establish.
Item codes. PL1…PL5Policies & Operations are proposed policies — standing rules for the project to accept, amend or reject; this is the layer rev 26 adds. R1…R5Risk Register are risks (things that might happen). D1…D4Debt Ledger are debts (costs already being paid every cycle). S1…S7The Strategy Already in Force are strategies already in force. RC1/RC2Root Causes are root causes. F1…F3Why the admin stopped — three compounding causes are the admin failure factors. E1…E5Easy Wins are the fast lane: trivial machine improvements that never compete with the difficult decisions. B2…B10Bets — for you to set are proposed bets — B1 was withdrawn along with a strategy row, and B3 and B4 moved to the Easy Wins lane at rev 26; the numbering keeps the gaps so earlier annotations still line up. C1…C9Credit Ledger are credits: investments that pay back every cycle, confirmed or still projected. P1…P5Pre-Mortem are pre-mortem entries — ways this report's own plan fails.
Policies & Operations
Solidus is technically healthy and strategically adrift. Both are true, and the gap between them is the whole story.
This section replaces the executive summary, because a summary describes and a policy decides. Everything a reader needs to act on is here; every rule links down into the evidence that produced it. The situation in brief: Solidus is technically healthy and strategically adrift — top-decile delivery machinery, one genuinely stalled initiative, a steward whose engineering quietly left, and a competitor that came back with revenue behind it. The project cannot win a fight for new merchants, but it holds one claim nobody can contest: it is the commerce framework you can still own in ten years. The rules below are what that diagnosis implies, written as standing policy rather than one-off advice. Read this register together with its two companions — §17Easy Wins — the fast lane and §18Bets — for you to set — because the three are one foundation: the policies govern what recurs, the fast lane ships the trivial machine improvements without ceremony, and the bets carry the calls that still need an owner's judgment. Accept all three layers and the strategy stands whichever role the project chooses.
- 60% → 0.8%Nebulab's share of commits, 2023 → last 12 months
- $45,760Already spent on the admin that never shipped
- 3 yr 3 moAge of the new admin, still version 0.4
- $133,750Cash held · nothing spent in thirteen months
Who accepts these, and what this report can and cannot mandate
The framework this report runs on (ESF v0.7 — see the notation note in Start Here) requires the mandate question to be answered before policy is proposed, so here it is, plainly. The author holds no mandate over Solidus. This is an outside audit; nothing below is accepted, and an outside analyst cannot accept it. Every PL row ships in the proposed state, addressed to the people the governance document actually empowers: the Core Team for anything touching code and releases, and the stakeholder vote for anything touching money observed.
Solidus is volunteer-delivered: nobody can be assigned a deadline they are not paid to meet, so a policy demanding sustained labour from named volunteers would fail on arrival. What the project can enforce, it already enforces well — by machine. Deprecations fail the build; style is linted, not litigated; merges require Core Team review observed. The rules below respect that ceiling: they are either policy statements that cost nothing to keep (naming a date, publishing a decision), allocation rules for money the collective already governs, or guidance with the enforcement left to existing machinery. None of them asks a volunteer to work.
One more obligation the framework imposes: check whether strategy work already exists before authoring any. It does. The lead maintainer published a coherent strategic position in May 2026 — governance breadth, licensing freedom, a deliberate rejection of the JavaScript-framework path web. The policies here join that position rather than competing with it; PL3Decisions are published where adopters can read them exists mostly to move it from a consultancy's blog into the project's own artifacts.
The proposed policy register
PL1 — Every replacement names the release that removes what it replacesdirection · proposed
The project engineers migrations well and never schedules them — RC1Migrations are engineered but never scheduled is the mechanism behind the largest recurring cost in the ledger, D1Three unfinished rewrites — the largest recurring cost in the project. Promotions has shipped a complete engine and a 190-line migration guide for two years, and no release anywhere says when the legacy engine goes. This rule closes the gap at the source: a successor ships as parallel opt-in only alongside a named removal release for the incumbent. Rails and Ruby both publish deprecation timelines this way; the statement costs nothing and assigns nobody labour. Its first invocation is B5Name the release that removes legacy promotions, which has been free to do for two years.
Addresses: RC1Migrations are engineered but never scheduled, D1Three unfinished rewrites
Relation: amends S3Ship replacements alongside the old version as opt-in by adding the exit criterion it lacks; reinforces S2Never break an existing store — a published date is how deprecate-before-removing stays honest
Operations: an exit-criteria line in the release-notes template (the same automation that already generates changelogs); the promotions gem's migrate-now advisory as the model document
Accepted by: Core Team (proposed)
Executed by: release checklist — an exit-criteria line in the release automation
Review: 2027-02-08
PL2 — Collective money buys named outcomes, not timeallocation · proposed
Every serious spending year funded a single engagement, and the one that failed — $45,760 for six "Agile Design Sprints" in 2023 — is the one that bought activity instead of an outcome (F1A definition of finished existed, and the money was not wired to it). The rule: a funded engagement names its deliverable, its completion criterion, and who carries the work after the money stops. The funding model itself is already settled and deliberate — independent developers paid from the collective while the maintaining firms stay on client work stakeholder — so this row ratifies a norm the project already holds and writes down the arm's-length standard that currently exists only in Slack and in one maintainer's head. Backtested against the record: the 2020, 2024 and 2025 engagements pass on shape and fail on succession; the 2023 purchase fails outright, and this rule is the difference.
Addresses: RC1An unfunded initiative sitting next to an unspent budget, R3The half-built admin becomes a permanent third state, F1The money was not wired to a definition of finished
Relation: fills a void — no written allocation rule exists; ratifies the unwritten funding norm stated by the Core Team at rev 25
Operations: the existing weekly stakeholder vote as the approval venue; the fiscal host's review as the independent check; the expense description itself carries the outcome and criterion, so inspection happens at approval time with no new machinery
Accepted by: stakeholder vote (proposed)
Executed by: the expense-approval step — an expense that names no outcome is sent back, not approved
Review: 2027-02-08
PL3 — Decisions are published where adopters can read themguidance · proposed
The Core Team holds explicit technical authority and the community meets weekly, yet no decision reaches a public artifact: the roadmap board is a changelog wearing a roadmap's name, and the clearest statement of project strategy lives on a consultancy's marketing blog (S1Reject the JavaScript-framework direction on purpose). A prospective adopter finds a well-kept record that the project had a past and no evidence it has a future. The rule: each Core Team decision lands within a month as a status post or a forward-looking roadmap item. This is publication, not governance — the decisions may already be getting made; nothing about them is visible. The blog has already half-resumed on its own, with one release announcement in May 2026 web; this rule turns that from an occasional act into a habit.
Addresses: D2Governance describes a project that no longer exists, D3Architectural decisions are never recorded, R4Spree takes the new-project market
Relation: ratifies S1Reject the JavaScript-framework direction on purpose by moving the published strategy into the project's own artifacts; reinforces S5Merge authority belongs to a self-appointing Core Team
Operations: both channels already exist and are dormant — restarting them costs an hour a month; E1Tick the already-done boxes on the porting checklist and E5Republish the strategy statement in the project's own artifacts are the first two acts and take minutes
Accepted by: Core Team (proposed)
Executed by: the two existing channels — status posts and forward-looking roadmap items — on a monthly reminder
Review: 2027-02-08
PL4 — Every parallel initiative gets a quarterly disposition, recorded publiclyapproval · proposed
The admin has been neither shipped nor cancelled for three years inside a governance structure that plainly permits either — authority exists, a venue does not (S5Merge authority belongs to a self-appointing Core Team, D2Governance describes a project that no longer exists). The rule gives the recurring decision an address: once a quarter, each parallel initiative is declared progressing, funded, paused until a named date, or cancelled, and the answer is written where outsiders can read it. The mechanism cannot fail silently, which is the property that matters — a quarter with no disposition list is itself visible. This is the row that would have caught the admin's stall in 2024 instead of letting an architecture that hides abandonment (R3The half-built admin becomes a permanent third state) hide it for two more years.
Addresses: R3The half-built admin becomes a permanent third state, D1Three unfinished rewrites, RC2The steward changed in the code but not in the governance
Relation: amends S5Merge authority belongs to a self-appointing Core Team — the authority stays exactly where it is; this adds the venue, cadence and record it never had
Operations: piggybacks on the existing weekly meeting, four times a year; the record is a roadmap-board item, which also feeds PL3Decisions are published where adopters can read them
Accepted by: Core Team (proposed)
Executed by: one agenda item per quarter in the existing weekly meeting; the disposition list lives on the roadmap board
Review: 2027-02-08
PL5 — A departing contributor's in-flight work is adopted or closed within a release cycleguidance · proposed
When the 2025 funded developer stopped, seven admin pull requests went stale where they sat, and the project's only rescue so far was one contributor volunteering by hand a year later (F3The last developer's work was abandoned mid-flight). That rescue worked — it moved to a fresh pull request on 30 July 2026, with the reviewer's preferred approach adopted observed — which proves the mechanism and indicts its coverage: one orphan in six found an adopter, by accident. The rule makes the accident routine. When a contributor departs, each of their open drafts gets an explicit adopt-or-close decision within one release cycle. Closing is a legitimate outcome; the only illegitimate one is the current default, indefinite limbo preserved by a compatibility rule that never expires anything.
Addresses: RC2The steward changed in the code but not in the governance, F2Built by one organization, handed to nobody, F3The last developer's work was abandoned mid-flight
Relation: fills a void, and ratifies the rescue mechanism the community has already demonstrated once
Operations: a saved GitHub search for drafts with no author activity in N months is the whole inspection; the nudge goes only to actual stalled threads, silent otherwise
Accepted by: Core Team (proposed)
Executed by: a stale-draft sweep (a saved search or scheduled action) plus a comment asking the one question: adopt or close?
Review: 2027-02-08
What the register deliberately does not cover
Two-way coverage is the rule this register is built under: every policy names the findings it addresses, and every top-ranked finding is either addressed or explicitly deferred with a date. Two deferments, stated rather than hidden:
- R2Two firms are 78% of the money and most of the code — concentration. No policy can conjure a third firm. The register reduces the blast radius (PL2Collective money buys named outcomes, not time requires a successor; PL5Departing work is adopted or closed handles the wreckage), but the concentration itself has no mechanism worth proposing today. Revisit when the next funded engagement lands, which is the moment a new party could plausibly enter.
- R5The new storefront breaks existing extensions by design — extension breakage. A stated property, not a hazard; bounded, with an obvious mitigation whenever someone wants it. Deferred until it bites someone specific.
The register was also backtested against this report's own Decision Log, as the framework requires: PL2Collective money buys named outcomes, not time would have reshaped the purchase that decision-log entry 31 dissects; PL4Every parallel initiative gets a quarterly disposition would have forced the question entries 07 and 34 spent three revisions reconstructing; PL3Decisions are published where adopters can read them is entry 28's correction turned into a standing rule. A policy that would have changed no logged decision is doing no work; these three carry the register.
The one conclusion to take away
Solidus cannot win the fight for new merchants — not on features, not on speed, not on funding. It has one uncontested claim left: it is BSD-3 licensed with no commercial entity that could ever relicense it, it has no JavaScript supply chain, it runs on one runtime, and its upgrade discipline is real and machine-enforced. Spree structurally cannot say this, because its Enterprise modules are commercial. Shopify would never want to.
That points at a role, not a comeback: the commerce framework you can still own in ten years. Serving the merchants who already chose it, rather than chasing the ones who never will. §15Who Solidus Can Still Serve–§18Bets — for you to set work through what that implies, and the policies above are the standing rules that survive whichever role is chosen.
The policy layer in one line: schedule what you replace, buy outcomes not time, publish decisions, give each initiative a quarterly disposition, adopt or close departed work — five rules, all proposed, none asking a volunteer to work.
Timeline
The whole story in one pass. The heavy markers are the moments the story hangs off; green is the one genuine bright spot.
solidus_admin to replace the ageing interface observed.solidus_promotions, alongside the existing promotions engine. Neither becomes the default observed.solidus_starter_frontend — a storefront maintained as its own repository for years — is renamed and absorbed into the monorepo as storefront/, bringing a 64-file, 5,510-line test suite with it observed.The arc in one line: forked from Spree in 2015, its creator gone by 2018, its steward's engineering gone by 2024 — and the machine still running on discipline the departed built.
The Money
Solidus's finances are entirely public, which is unusual and useful — this section rests on records rather than guesses. All figures from the Open Collective API observed; the balance and the outgoing ledger were re-checked on 8 August 2026 for this revision.
How the money is structured
Solidus is not a company or a foundation. It has no legal existence. Its money is held by Open Source Collective, a US non-profit acting as a "fiscal host": it receives donations, holds the balance, and pays out expenses that the project's administrators approve. This is a common arrangement for open-source projects and provides a genuine external check, since someone outside the project reviews every payment.
| Item | Amount |
|---|---|
| Cash held | $133,750 |
| Received in total since 2018 | $329,677 |
| Paid out in total | $154,612 |
| Host and payment-processing fees (residual, computed on the 25 Jul snapshot) inferred | ~$42,885 · ≈13% |
| Income over the last twelve months | $26,322 |
A note on that last figure. Open Collective's public page labels it "estimated annual budget," which sounds like a plan. It is not — it is simply what came in over the previous year. Nobody has budgeted anything.
Where the money comes from — and who stopped giving
Cumulative totals flatter the picture badly, because they include sponsors who left years ago. The honest number is active recurring contributions, of which there are nine, totalling $1,931 per month — a set re-confirmed unchanged on the August 2026 billing cycle observed:
| Still paying monthly | Amount | Share | Since |
|---|---|---|---|
| Super Good Software | $750 | 39% | 2019-01 |
| Nebulab | $750 | 39% | 2019-01 |
| 3llideas | $100 | 5% | 2025-11 |
| DevOutsourcing | $100 | 5% | 2024-03 |
| FCP Euro | $100 | 5% | 2020-03 |
| TCW Equipment | $100 | 5% | 2019-10 |
| wemove digital solutions | $20 | 1% | 2019-08 |
| weLaika | $10 | <1% | 2019-10 |
| Karma Creative — formerly a $19,561 cumulative sponsor | $1 | <1% | 2019-05 |
78% of all recurring money comes from the two agencies that also maintain the code. Remove them and the entire rest of the world contributes $431 a month to a framework that processes real payments for real stores.
Karma Creative's decline from major sponsor to a symbolic $1/month is the clearest single illustration of the trend.
Over thirty sponsors have cancelled, including large ones: Engine Commerce ($1,000/month), Modded Euros ($850 across three subscriptions), Firstleaf ($325), Magmalabs ($325) and Deseret Book ($200). Most are merchants rather than agencies — actual stores that stopped paying observed.
An important timing detail
Cancellations by year: 2019: 7 · 2020: 7 · 2021: 7 · 2022: 4 · 2023: 5 · 2024: 2 · 2025: 5 · 2026: 2 .
This is steady attrition since 2019, not a recent collapse — and there is no spike after Spree's commercial relaunch in April 2025. In fact 2024 and 2026 are the two lowest years on record. Whatever is wrong with Solidus, Spree did not cause it. This matters a great deal for §16Choose a Role.
Where the money went — and when it stopped
The project has paid 67 expenses totalling $154,612. The balance is not sitting there because nobody knows how to spend it. The project knows exactly how, and has done so repeatedly.
| Year | Paid out | Expenses | Where it went |
|---|---|---|---|
| 2019 | $11,768 | 10 | Conference costs — Sean Denny 43%, Cindy Backman 42% |
| 2020 | $35,736 | 24 | Peter Berkenbosch 80% — monthly "Development & Maintenance" |
| nothing at all | |||
| 2022 | $500 | 1 | One conference video-editing invoice |
| 2023 | $45,760 | 7 | The admin — Nebulab 79%, Andrea Iurisci 21%. 100% of the year. |
| 2024 | $32,506 | 16 | Logicielle B.V. 100% — 16 development invoices, Aug–Dec |
| 2025 | $16,888 | 6 | "e.c441" 100% — 6 development invoices, Feb–Jul |
| nothing at all |
| Recipient | All-time | Years active |
|---|---|---|
| Nebulab | $36,419 | 2023 ($36,000, admin) · 2020 ($419) |
| Logicielle B.V. — identity unverified | $32,506 | 2024 only |
| Peter Berkenbosch | $28,650 | 2020 only |
| "e.c441" — anonymized payee | $16,888 | 2025 only |
| Sean Denny — conference | $11,262 | 2019, 2020 |
| Andrea Iurisci | $10,250 | 2023 ($9,760, admin) · 2020 ($490) |
| Cindy Backman, Thomas Sample, Daniel Gayfer, Shana Remigio, Matteo Galliani | $7,183 | 2019, 2022 |
| Total | $143,158 | 64 paid expenses |
What the yearly view reveals: one funded engagement at a time
In every year the project spent seriously, essentially all of it went to a single engagement observed:
- 2020 — a funded maintainer, Peter Berkenbosch, on a monthly retainer (80% of the year)
- 2023 — the admin push, Nebulab plus a designer (100% of the year)
- 2024 — a funded developer, Logicielle B.V. (100% of the year)
- 2025 to July — a funded developer, "e.c441" (100% of the year)
And between them: 2021 and 2026 are completely dry, 2022 nearly so.
This changes how July 2025 should be read. It is not the moment a project gave up — it is the third time a funded engagement ended and was not renewed. The project has hired a maintainer three separate times and stopped three separate times. Dry years are part of its normal rhythm.
Which sharpens the open question in §22What I Could Not Establish considerably. The right question is not "why did funding stop?" but "why was this engagement not renewed, when the two previous gaps were eventually filled?" Thirteen months is already longer than the 2021–22 gap that preceded the 2023 admin push.
2023 is the line that matters
Six payments of $6,000 each to Nebulab, every one labelled "Solidus Admin Dashboard Agile Design Sprint 1–6," plus $9,760 to Andrea Iurisci for an "Admin Panel Redesign Analysis" observed.
The project already bought the admin rewrite, for roughly $45,760. It never shipped. What the money purchased was six sprints — activity — with no shipped screens, no completion date and no owner named beyond the final sprint. This is the purchase PL2Collective money buys named outcomes, not time exists to make impossible.
On process: two earlier Nebulab claims of $7,320 each were rejected before the six approved sprints were paid. The approval process does exercise scrutiny.
Funded development continued after that — $32,506 to a Dutch company across 16 invoices in late 2024, $16,888 to an anonymized payee across six invoices in the first half of 2025 — then stopped completely with the expense paid on 5 July 2025. Thirteen months of income have arrived since, with nothing going out. Re-checked 8 August 2026: the most recent debit in the ledger is still the July 2025 invoice observed.
How firm is the ‘unspent’ claim?
Firmer than most figures in this report, because it was challenged and re-checked — twice now. The balance is reported by two independent Open Collective endpoints in exact agreement; it is not derived by subtracting expenses from income, so it does not depend on any arithmetic here.
A first pass looked only at paid expenses, which would have missed money approved and awaiting payout. Querying every state returned 67 expenses: 64 paid, 3 rejected, and none pending, approved or processing. The most recent expense of any status is from July 2025. So nothing is committed and in flight observed. The 8 August re-check read the debit ledger again and found the same picture; the one thing it could not read unauthenticated is expenses submitted but not yet approved, a limit noted rather than hidden observed.
Two reconciliation gaps remain open and are worth naming. The 64 paid expenses sum to $143,158, against a reported total spend of $154,612 — an $11,453 difference, most plausibly payout fees. And received-minus-spent exceeds the balance by $42,885, or 13% of everything received, consistent with a host fee plus payment processing. Neither is verified inferred. Also worth noting: 2021 saw zero expenses, so a dry year is not unprecedented.
An important limit on what ‘idle money’ means
The $133,750 describes the Open Collective account only. It is not a measure of what is being invested in Solidus.
Super Good Software contributed roughly 188 commits in the last twelve months, and Nebulab still pays the top sponsorship tier. At any consulting rate, that donated engineering time dwarfs the entire cash balance. The cash is idle; the project's total investment is not.
The accurate and narrower finding: the pooled, collectively-governed money — the only money the community can direct as a body, through the one mechanism its governance actually defines — has been static for thirteen months while its own stated priorities went unfunded. That remains a real finding. It is not "nobody is investing in Solidus."
Who can spend it
Seven people are administrators on Open Collective and can approve expenses: tvdeyen, Gregor MacDougall, Alberto Vena (Nebulab), Matteo Latini, Andrea Iurisci, Alessandro Desantis (Nebulab co-founder) and Jared Norman (Super Good) observed. At least two are from the organization that stopped contributing code.
On the obvious question
Nebulab is both the largest single recipient of project money ($36,419) and one of the approvers. That deserves stating plainly — and so does the context that makes "extraction" the wrong reading: Nebulab has contributed $80,750 and received $36,419, a net contribution of $44,331. They still pay the top tier every month. Two of their claims were rejected. An independent fiscal host reviews every payment.
The defensible finding is narrower and still serious: a $45,760 related-party payment was approved with no completion criterion attached, and produced no shippable outcome. The gap is the absence of an arm's-length standard for paying an insider — not misappropriation.
A related theory — that the sponsorship was a play for voting power — does not survive the mechanics. Voting weight equals monthly contribution, capped at 1000; Nebulab and Super Good are tied at $750 and neither has spent the extra $250 that would max the cap. Votes govern only how funds are spent and who becomes an advisor; they confer no authority over what code gets merged. And the economics run $44k the wrong way observed.
At rev 25 the arm's-length standard this finding said was missing turned out to exist as a stated norm: maintainers prefer not to take collective money at all — "I prefer to avoid any perception that those of us maintaining Solidus are profiting directly from the OpenCollective funding" — and funds-to-agencies work is fine "as long as it's transparent and fairly priced," with skilled third parties preferred stakeholder. A norm stated in Slack is not a governance document, so the finding narrows rather than closes: the standard exists in the owner's head and now on the record; it is still written nowhere the next approver would read. PL2Collective money buys named outcomes, not time is that paragraph, drafted.
The money in one line: funded development stopped in July 2025, thirteen months of income have arrived since, and $133,750 sits unspent.
The Product
What actually exists in the repository, and the pattern connecting the three unfinished rewrites.
| Component | Ruby | Specs | ERB | Started | Default? |
|---|---|---|---|---|---|
solidus_core — the commerce domain | 543 | 312 | 17 | 2015 | yes |
solidus_admin — new admin | 235 | 93 | 111 | 2023-05 | no |
solidus_promotions — new promotions | 165 | 113 | 78 | 2024-06 | no |
solidus_legacy_promotions — old promotions | 101 | 92 | 58 | 2024-01 | yes |
solidus_backend — old admin | 79 | 87 | 277 | 2015 | yes |
solidus_api — REST API | 57 | 41 | 0 | 2015 | yes |
storefront/ — Rails app template | 54 | 64 | 103 | 2026-06 (repo: years) | via generator |
solidus_sample — seed data | 25 | 1 | 0 | 2015 | yes |
The defaults column was re-checked on 8 August 2026: the meta-gem still names solidus_api, solidus_backend, solidus_core, solidus_legacy_promotions and solidus_sample, and still omits solidus_admin and solidus_promotions observed.
The ERB column is where the old admin actually lives. solidus_backend has 79 Ruby files and 277 view templates — it is a server-rendered UI, and counting its Ruby files badly understates it. The new admin has 111 templates against the old one's 277, which is an independent measure of how far the port has to go (§08Admin Autopsy).
Three parallel components — but three different stories
Counted together they suggest a systemic failure to finish. Looked at individually, only one is in trouble.
| Area | Old | New | Age | What it actually is |
|---|---|---|---|---|
| Promotions | legacy_promotions | solidus_promotions | 2 yr 2 mo | a managed migration, missing only a date |
| Storefront | solidus_frontend | storefront/ | years, as its own repo | a success — see below |
| Admin | solidus_backend | solidus_admin v0.4 | 3 yr 3 mo | the one genuine stall |
Promotions is not a stalled rewrite — it is a textbook staged migration
The gem ships a 190-line migration guide covering installation, migrating existing promotion data, switching store behaviour, syncing legacy order promotions, handling custom storefronts, porting custom rules, and finally removing the legacy gem from the Gemfile observed.
Its README states the intent plainly: "It is slated to replace the promotion system in the legacy_promotions gem… While the current version of Solidus still installs the legacy promotion system, we advise a migration at the earliest convenience to avoid having to rush the migration in the future."
The old engine ships by default on purpose — rule S2Never break an existing store — deprecate before removing requires an opt-in period before a breaking data migration. The architecture change is justified on performance grounds (promotion handling centralized in the order updater).
The one thing genuinely missing is a date. There is no deprecation timeline anywhere — no "Solidus 5 removes this." The path is fully engineered; the cutover is unscheduled. That is a much smaller and more actionable finding than "a stalled rewrite," and it is precisely the case PL1Every replacement names the release that removes what it replaces generalizes.
The storefront is a success — and the reason why is instructive
Eleven commits over six weeks, by four people from two organizations including Alberto Vena of Nebulab observed. It shipped: renamed in, code coverage set up, an extra PayPal spec copied over, README aligned with sibling components, licence and docs cleaned up.
What arrived with it was not a seven-week-old skeleton. solidus_starter_frontend had been maintained as its own repository for years, and it brought 64 spec files and 5,510 lines of tests — components, controllers, helpers, mailers, request specs including authorization, and 19 system specs covering authentication and caching. Those specs are copied into every generated store, and CI installs a store and runs them end to end on every push observed.
It worked because it was not a rewrite. solidus_starter_frontend already existed, already worked, and was already maintained as a separate repository. The June 2026 work absorbed a finished thing into the tent rather than building a new one from zero.
Contrast with the admin and promotions, both built new from nothing. The lesson the project has already demonstrated to itself: bounded, finishable work with a clear end state gets finished, and cross-organization collaboration still functions when the work has that shape.
The residual cost is real but narrower than earlier stated: two promotion engines account for 205 test files covering the same domain, and every new installation still carries two admins observed.
Development volume by year
The 2023 spike and its collapse is not a general fatigue curve. It is one organization arriving and leaving — see §06The People.
How Solidus is actually used — and the near-absence of public prior art
For a commerce platform, the most persuasive evidence is a real store. A search of public repositories depending on Solidus returns roughly thirty results observed — and almost none are production stores:
- Extensions and tooling —
boomerdigital/solidus_flexi_variants,solidus_pca_address_validation,jtapia/solidus_picker,Whelton/solidus_editor,StemboltHQ/solidus_chimpy - Demos, templates and learning projects —
mrenoon/solidus-template-store,kennyadsl/solidus-searchkick-example,ArkieCoder/dockerized-solidus, bootcamp exercises - Agency reference work —
madetech/market_townandorder_reporting,nebulab/bretelline,peterberkenbosch/blogstore
There is essentially no public example of a real Solidus store. This is expected — commerce implementations are proprietary — but it has a strategic cost that Spree does not pay: Spree offers a hosted sandbox and a one-command scaffold, so an evaluator can see the thing running in minutes.
Jared Norman named this himself in How to Fail at Solidus, observing that many Solidus implementations remain invisible to the community web. A platform whose successes are all private competes at a permanent evidence disadvantage — and the one artefact that would close the gap cheaply, a runnable public demo store, does not exist.
The extension ecosystem
Solidus keeps optional capabilities in separate repositories. Of the 35 in the official organization, those still worked on in 2026 are payments (Stripe, PayPal), subscriptions, authentication, translations and developer tooling. Dormant since October 2023: the GraphQL API, webhooks, and the old storefront observed. The ecosystem is thinnest exactly where Spree is investing hardest — APIs and headless storefronts.
The product in one line: three parallel rewrites read as systemic failure to finish, but promotions is a managed migration, the storefront a success — only the admin has stalled.
The People
Who writes the code, and the handover that never happened. This is the causal centre of the report.
| Who | Commits | Share |
|---|---|---|
| Super Good Software | ~188 | 38% |
| Martin Meyerhoff — an individual, with no company behind him | 147 | 30% |
| blish.cloud — von Deyen, Karnatz | 74 | 15% |
| Those three combined | ~409 | 83% |
| Nebulab — 60% of commits in 2023 | 4 | 0.8% |
The withdrawal, year by year
| Person (organization) | 2022 | 2023 | 2024 | 2025 | 2026 |
|---|---|---|---|---|---|
| Elia Schito (Nebulab) | 133 | 696 | 46 | 4 | |
| Alberto Vena (Nebulab) | 70 | 232 | 52 | 12 | 3 |
| Rainer Dema (Nebulab) | — | 168 | 2 | ||
| Super Good Software (all) | 34 | 3 | 140 | 62 | 136 |
Nebulab supplied roughly 1,096 of 1,810 commits in 2023 — about 60% — and roughly 3 of 223 in 2026. No announcement of this transition was ever made publicly; extensive searching found nothing web. This is a change in who writes the code, not necessarily in who steers the project. The two are separate roles, and only one of them is visible from outside.
Nebulab is still active — just elsewhere
They remain a 27-person operating consultancy and still pay the top sponsorship tier. But their services page now lists "Shopify Development" at exactly equal weight with "Solidus Development" web. A steward that diversified into a competing platform, still funding while its engineers moved on, matches the commit curve precisely.
Where decisions get made — and where they don't
| Interface | Guaranteed turnaround? | What actually happens |
|---|---|---|
| Pull request → merge | no | 40 open; the oldest date from 2021 and 2022 — but see the note below |
| Joining the Core Team | no | "send a Slack DM to Alberto Vena" — a person, not a process |
| Becoming a partner or advisor | no | "send a Slack DM to Sean Denny" |
| Deciding how to spend funds | partial | a stakeholder vote at a documented weekly meeting |
| Deciding technical direction | authority yes, venue no | Core Team holds final say; no stated cadence, quorum or record |
The decision-making gap is narrower than it first looks — and harder to see from outside
Two things in the governance document are worth quoting exactly, because together they define the gap precisely observed.
Technical authority is assigned. "Members of the core team make the final decision as to what goes into the core and any other non-marketing material… hosted in the official Solidus GitHub organizations." So there is a body empowered to decide whether the new admin ships or is cancelled. It is the Core Team, and the power is explicit.
Recurring meetings exist, and are scoped away from that question. Stakeholders "coordinate with weekly meetings and contribute to Solidus usually in non-technical ways, for instance by choosing what conferences to attend or organize, by identifying marketing opportunities or by deciding how to use the funds in Open Collective." So the one documented standing forum is, by its own description, about conferences, marketing and money.
What is missing is therefore not authority and not meetings. It is a venue, a cadence and a record for exercising the authority that exists. The Core Team can decide the admin's fate at any time; nothing states when they convene to do so, what constitutes a decision, or where the outcome is written down. PL4Every parallel initiative gets a quarterly disposition proposes exactly and only that missing piece.
Open source, private decisions
This is where the gap becomes a finding rather than a technicality. Both artefacts that could carry public technical direction carry almost none.
- The public roadmap board holds 76 items — 65 merged pull requests and 7 closed issues, against 3 open forward-looking ones. It records what was done observed.
- The blog ran monthly status updates from May to October 2025, went quiet, and has published one release announcement since — for v4.7, in May 2026 web.
Whether decisions are being made in Slack or in the weekly meeting, an outside reader cannot tell — and neither can a merchant deciding whether to build on this platform for the next decade. Nothing in this audit establishes that no decisions happen; it establishes that almost none are published.
That reframes the fix and makes it much cheaper than "create a governance process." The Core Team already has the authority and the community already meets weekly. The missing artefact is a published record, and the project owns two channels purpose-built to carry one. Restarting the status posts as a habit rather than a release-day exception, and filing forward-looking items on the roadmap board, converts an invisible process into a visible one at close to zero cost — which is PL3Decisions are published where adopters can read them in one sentence.
Limit of this finding: I did not establish whether meeting minutes exist somewhere non-public. The claim here is only that no record is discoverable from outside inferred.
The open pull request pile is partly external noise — and it was actively handled
Do not read all 40 open pull requests as maintainer neglect. In April 2026 Jared Norman posted an announcement explaining a sudden wave of first-time contributions: an online job board had been setting candidates the task of fixing Solidus issues as a screening step observed.
His account is worth quoting for what it shows about stewardship: "many were of low quality, having been generated by LLMs or users with no experience with the project… this wasn't something we signed up for or wanted and created undue maintenance burden. I've contacted the job board and had them reach out to the creator of the listing to remove this step." He then went out of his way to encourage genuine newcomers and point them at good first issues.
That is a maintainer diagnosing an external cause, intervening upstream to stop it at source, and protecting the contributor funnel while doing so. It is evidence of active stewardship, and it cuts against reading the backlog as decay.
The people in one line: Nebulab supplied roughly 60% of all commits in 2023 and 0.8% over the last twelve months, and no announcement was ever made.
The Machine
The automated systems that build, test and release the software. Solidus is genuinely strong here — and every gap points the same direction.
| Capability | Present? | Detail |
|---|---|---|
| Tests run on every change | yes | eight separate test jobs |
| Breadth of test matrix | strong | Rails 7.2 / 8.0 / 8.1 × Ruby 3.2 / 3.3 / 3.4 / 4.0, three databases |
| Deprecated code fails the build | yes | SOLIDUS_RAISE_DEPRECATIONS: true — this is what makes the upgrade promise real |
| Code style enforced automatically | yes | standardrb, ERB and JavaScript linting |
| Test coverage measured | yes | six components report to Codecov |
| Releases automated | yes | changelog generated from labels |
| Fixes back-ported to old versions | yes | automated across five maintained lines |
| One-command development setup | yes | Docker Compose, bin/setup |
| Security disclosure policy | strong | HackerOne program, 5-day acknowledgement, three-phase coordinated disclosure |
| Security patch window | yes | 18 months; 4.7, 4.6 and 4.5 currently supported |
| Automated security dependency updates | yes | stated in the security policy; enabled through GitHub rather than a config file |
| Release-account protection | yes | multi-factor authentication required for RubyGems release permissions |
| Review control | yes | two mandatory Core Team reviews before merge |
| Automated routine dependency updates | no | no Dependabot or Renovate config for non-security version bumps — E2Renovate or Dependabot config for routine updates |
| Dependency audit step in CI | no | no bundler-audit or brakeman job — but see the disclosure apparatus above; E3A bundler-audit job in CI |
| AI-agent harness | no | no AGENTS.md, no CLAUDE.md, nothing — re-checked 8 Aug 2026; E4An in-repo agent harness |
| Architecture docs / decision records | no | none; the roadmap repository dormant since May 2023 |
| Review routing | yes | CODEOWNERS routes every path to the core team — see note |
| Contributor templates | yes | pull-request and issue templates, inherited from the organization |
Security is the best-run process in the project
The repository has no SECURITY.md, which invites the conclusion that a payments framework is running without a disclosure policy. It is not. The policy lives at organization level and points to a published process that is considerably stronger than most projects this size manage observed web:
- A HackerOne vulnerability disclosure program, with reports explicitly routed away from public channels.
- A stated response commitment — "Your report will be acknowledged as soon as possible and we'll try to get in touch within 5 days" — with updates at least every five business days, and a named escalation path if that lapses.
- A three-phase coordinated disclosure: assign a handler and audit affected versions; prepare fixes privately via GitHub Security Advisories for every supported release; then publish advisory, mailing-list notice, gem releases and a blog post "within the same business day."
- 18-month security support, currently covering 4.7, 4.6 and 4.5.
- Two mandatory Core Team reviews before any merge, and multi-factor authentication required for RubyGems release permissions.
- Automated security dependency updates — stated in the policy, which resolves the one thing the repository could not show.
There is a track record behind it: five published advisories between 2020 and 2022, severity-rated, one carrying a CVE observed.
Two observations worth keeping. First, the supported-versions list is current — it names 4.7, released April 2026 — so this policy is being maintained while the roadmap is not. It is a fair signal of what this project keeps up when it judges the stakes high enough. Second, no advisory has been published since 2022. That is four quiet years, which could mean nothing was found or could mean the process has gone as quiet as the rest; nothing here distinguishes the two inferred.
The machine in one line: every change tested against four Ruby–Rails combinations with the newest of each adopted within weeks of release, deprecations failing the build, fixes back-ported automatically — top-decile delivery machinery for a project this size.
On the single-line CODEOWNERS — not a defect
.github/CODEOWNERS contains one rule: * @solidusio/core-team observed. Against a generic checklist that reads as missing granularity. Against this project it is arguably the right configuration.
Granular ownership earns its keep when there are distinct sub-teams to route between. Solidus has 27 contributors a year and three parties writing 83% of the code (§06The People); there is no sub-team structure to route to. Worse, assigning components to named individuals in a project whose defining failure mode is people leaving would convert every departure into a stalled queue — precisely what happened to the admin when its owner stopped contributing.
The catch-all instead guarantees that every path reaches whoever on the core team is available, and it is the natural mechanism behind the security policy's stated "two mandatory Core Team PR reviews before merging" (§07The Machine). It is plausibly load-bearing rather than vestigial.
What I could not verify: branch-protection settings and core-team membership both require organization admin scope, and returned permission errors rather than absences. So the review requirement rests on the published policy web, not on direct observation of the enforcement.
The Rails-way edge — where Solidus is a generation behind Rails itself
Solidus's core strategic claim is that it does things the Rails way. That claim is worth auditing against what the Rails way currently is.
| Concern | Rails 8 default | Solidus | Verdict |
|---|---|---|---|
| Front-end interactivity | Hotwire — Turbo + Stimulus | Turbo + Stimulus in the new admin; jQuery in the old one | current where it is new |
| JavaScript delivery | importmap, no Node | importmap, no Node | current |
| Asset pipeline | Propshaft | require "sprockets/railtie" in core; sprockets-rails in the old admin | a generation behind |
| CSS | various; Tailwind well supported | tailwindcss-rails in the new admin, Sass in the old | mixed |
Rails 8 ships Propshaft as the default asset pipeline; Sprockets is the previous generation web. Solidus core hard-requires Sprockets observed, which means every Solidus application is pinned to the legacy pipeline regardless of what the host app would otherwise choose.
This is the sharpest form of the "Rails way" gap: the differentiator is not "we use Rails," it is "we use Rails as it is done now." On the new admin, Solidus is current. On the foundation every store loads, it is not. And the coupling runs through solidus_core, so it is not something an individual store can opt out of.
What the Sprockets pin actually costs — the installer story
This is not an abstract modernization point. It is the direct cause of Solidus's longest-running class of bug reports, and the connection is documented inside the project's own CI.
The install path is already covered by continuous integration, and thoroughly. solidus_installer.yml runs on every push and pull request to main and it installs the native image library, runs the real installer with real flags, boots the application and asserts the homepage renders, verifies the resolved payment-gem version, and then runs the generated application's own test suite with coverage reporting. A second workflow covers the extension-generator path observed.
But the composite action that CI calls does something before it runs the installer:
prepare_solidus_app/action.yml
# Due to a bug in sprockets-rails we need to manually add the sprockets manifest
# into the generated rails app *before* running any rails commands…
mkdir -p app/assets/config
cat <<MANIFEST > app/assets/config/manifest.jsThe composite action patches the app before the installer runs — a workaround CI carries so the install path stays green.
Continuous integration is green on an install path the documentation does not describe. The official guide gives two commands. CI quietly performs three. A developer following the guide hits precisely the bug that CI works around — and the explanation lives in a code comment rather than anywhere a user reads observed.
That is the mechanism behind a decade of install issues: #6327installer fails with a Sprockets error (installer fails with a Sprockets error), #5410the new admin breaks asset compilation when the host app has Tailwind (the new admin breaks asset compilation when the host app has Tailwind), #6516align the install instructions with the storefront (open — align the install instructions with the storefront), and #6035the installer may fail silently (open 19 months — the installer may fail silently).
Two further limits on what CI proves: it installs from the working tree rather than the released gem, and it passes --sample=false, so sample-data loading — which is on by default for real users — is never exercised.
Waiting for upstream is not available
The upstream fix — rails/sprockets-rails #546, "Warn instead of raising on missing manifest.js" | open since Feb 2025, unmerged |
Last sprockets-rails release | v3.5.2, July 2024 |
| Solidus's own dependency line | sprockets-rails != 3.5.0 — a defensive exclusion of a bad release |
| Rails 8 | already replaced it with Propshaft |
The fix Solidus is implicitly waiting on sits unmerged in a gem that has not shipped in two years and has already been superseded upstream observed web.
How deep does the coupling actually go?
Unevenly — which is what makes a staged migration practical.
| Component | Coupling | Port difficulty |
|---|---|---|
solidus_core | require "sprockets/railtie", plus one asset ERB file | shallow |
solidus_admin (new) | none — importmap and tailwindcss-rails | already compatible |
solidus_backend (old) | 151 Sprockets directives, concatenating vendored jQuery, Backbone, Handlebars, select2, underscore | deep |
The core coupling is smaller than the headline suggests. Its single asset ERB uses ERB for exactly one purpose — interpolating the mount path into Spree.mountedAt() — which a meta tag replaces in an afternoon. Note that only two ERB files in the whole tree are asset-pipeline files at all; the rest are view templates responding to AJAX requests, which Propshaft never touches.
The old admin is the anchor — and there is a way around it
Because the meta-gem still ships solidus_backend, defaulting new installs to Propshaft appears to depend on resolving the admin question first — a dependency on the one decision this project has not made in three years.
It can be sidestepped. The old admin's JavaScript is legacy and frozen; nobody is writing new Backbone views in 2026. Sprockets is being used to build those assets on every boot when what is actually needed is the built artifact. Compile all.js and all.css once, ship them as static files, and Propshaft simply serves them.
This decouples the asset-pipeline decision from the admin decision entirely — and it is the same pattern that made the storefront succeed in §05The Product: absorb a finished thing rather than rebuild it.
The runtime story, which matters more than it looks
Solidus has no package.json, no lockfile, and no npm dependency graph anywhere in the repository observed. It uses importmap-rails, a tool that exists specifically to avoid needing Node.js, and tailwindcss-rails, which ships a standalone binary. There is JavaScript — jQuery in the old admin, Turbo and Stimulus in the new one — but this is the Rails-native style of adding behaviour to server-rendered pages, not a separate application.
Spree, by contrast, carries package.json, pnpm-lock.yaml, a pnpm workspace, Turborepo and Biome, plus eleven JavaScript packages observed.
The practical difference for a merchant: one runtime to operate and no JavaScript supply chain to audit, versus two of each. This is one of the few genuine and durable advantages Solidus still holds, and §16Choose a Role builds on it.
Admin Autopsy
The most expensive initiative in the project's history, examined closely: what state it is actually in, and the three reasons it stopped. Everything here was read directly from the repository.
- v0.4.0Version, after three years and three months
- switched offOrder and product editing, by default
- 27 screensIn the old admin with no replacement at all
First, credit where due: the new admin is well built. It is a modern Rails engine using ViewComponent, Turbo, Stimulus and Tailwind, with 132 components and 93 test files. This is not a quality problem.
Why the admin outranks everything else in this report
For a hosted platform the storefront is the product. For a framework it is the opposite. Solidus's storefront ships as an application template — you copy it into your app and change it, and every serious merchant does. Nobody runs the reference storefront unmodified; customizing it is the point.
The admin is the component merchants use as delivered, every day, to run the business: take a payment, process a refund, edit a variant, adjust stock, handle a return. It is the one part of a commerce framework that has to work out of the box, because it is the one part nobody wants to rebuild.
That inverts the intuition that the customer-facing surface matters most. A merchant can route around a storefront they dislike by writing their own. They cannot route around a missing returns workflow. Which is why the 27 unported screens are the daily-operations core rather than a long tail, and why R3The half-built admin becomes a permanent third state rather than the competitive risk sits at the top of the register.
Finding 1 — the two screens a merchant lives in do not work by default
Rails applications declare which web addresses exist in a routes file. Solidus's new admin wraps its most important routes in a condition:
admin_resources :products, only: [:show, :edit], constraints: -> { SolidusAdmin::Config.enable_alpha_features? && … } |
admin_resources :orders, except: [:destroy, :index], constraints: -> { SolidusAdmin::Config.enable_alpha_features? } |
And in the configuration file: preference :enable_alpha_features, :boolean, default: false.
Out of the box, the new admin can show a list of orders and a list of products — but cannot open either one. Viewing an order, editing a product: the screens a shop manager spends all day in, behind a switch that is off. What does work by default is the settings area.
This is also the team's own published verdict that the work is not ready. It has been off for years.
Finding 2 — most of what exists is partial
The new admin has 32 controllers against the old admin's 50. But the raw count overstates progress. Thirteen of the 32 inherit generic create/read/update/delete behaviour automatically — and all thirteen are low-traffic settings screens (reasons, categories, zones, roles). Of the seventeen hand-written ones, six can only list and delete, with no way to create or edit: payment methods, tax rates, shipping methods, stores, option types and taxonomies.
Finding 3 — 27 screens have no replacement at all
- The entire returns and refunds workflow — payments, refunds, reimbursements, return authorizations, return items, customer returns, cancellations
- Product data beyond the product record — variants, prices, images, option values, product properties
- Merchandising — taxons (the category tree), stock movements
- The dashboard itself
- Plus general settings, themes, locales, API keys, search, customer details
What was ported is the configuration long tail. What is missing is the daily operations core. "64% complete by controller count" badly overstates completeness measured by what a merchant actually does.
Finding 4 — the replacement depends on the thing it replaces
The new admin's package definition declares a hard dependency on solidus_backend — the old admin — and its components link out to old-admin web addresses for adjustments, stock movements and store-credit history observed.
The new admin requires the old admin to function. It is an overlay, not a replacement. This is why the default installation still ships the old admin and why every new store gets both. It also means that even at full feature parity, removing the old admin would be a second project, not the finish line of this one.
Why it stopped — three compounding causes
F1 — A definition of "finished" existed, and the money was not wired to it
$45,760 purchased six "Agile Design Sprints" and one "Redesign Analysis." Nothing in that purchase named a shipped screen, a completion date, or an owner beyond the last sprint.
What makes this sharper is that a completion checklist already existed. Issue #5391the new admin's porting checklist — open since September 2023, opened September 2023 and still open, sets out the porting plan with an explicit sequencing rationale — "We want to tackle the easy pages first, so we can slowly improve and augment our UI kit components and then reuse it to migrate more complex pages (e.g. promotions)" — followed by a task list observed:
| #5391the new admin's porting checklist — open since September 2023 · "low-hanging fruits" | Ticked? | Actual state in the code today |
|---|---|---|
| Settings > Zones | no | full CRUD via ResourcesController — done |
| Settings > Taxes | no | tax categories done; tax rates list-only |
| Settings > Returns & Refunds | no | reason lookups done; the returns workflow absent |
| Settings > Shipping | no | categories done; methods list-only |
| Settings > Payments | no | list-only |
| Settings > Stores | no | list-only |
Note what that checklist is: the six easiest screens in the application — and see below for why choosing them first was the mistake. The project did define what finished meant, published it, and then stopped tending the definition. Not one box has been ticked in three years, including for work that is demonstrably complete — re-confirmed on 8 August 2026, all six boxes still empty observed. There was also a public narrative: the Q2 2023 blog post reported that "the new admin experience required some upfront effort; now that the main components have been built, implementing the remaining sections will be easier and faster" web.
The failure is therefore not an absent gate. It is a gate that nobody was accountable for closing, and a purchase that bought sprints rather than the ticks.
F2 — Built by one organization, handed to nobody
2023 authorship of the admin: Elia Schito 370, Rainer Dema 132, Marc Busqué 102, Alberto Vena 6 — roughly 98% from Nebulab's orbit. 2024 dispersed across six people as they wound down. 2025 was carried by a single individual, Eugene Chaikin (who commits as chaimann), with 151 of 193 commits. 2026 has 19 commits across five people and no owner at all observed.
F3 — The last developer's work was abandoned mid-flight
Seven pull requests open for a year invite the reading that finished work is waiting on reviewers. Reading the actual threads — commits, inline review comments and conversation — gives a more specific answer observed:
| Pull request | Author | State | Last human commit | Review activity |
|---|---|---|---|---|
| #6302payment methods create/edit — draft payment methods create/edit | chaimann | draft | 2025-07-04 | none at all |
| #6298tax rate create/edit — draft tax rate create/edit | chaimann | draft | 2025-06-27 | none at all |
| #6296product categories — draft product categories | chaimann | draft | 2025-06-17 | none at all |
| #6236option types — draft option types | chaimann | draft | 2025-05-26 | none at all |
| #6228store create/edit — draft store create/edit | chaimann | draft | 2025-06-27 | none at all |
| #6232shipping methods — draft shipping methods | JustShah | draft | 2025-05-07 | 4 inline comments, reviewed by elia and a Copilot bot |
| #6295confirmation dialog — adopted by another contributor, July 2026 confirmation dialog | chaimann | ready | 2025-06 | adopted by another contributor, July 2026 |
A caution about timestamps. GitHub reports several of these drafts as updated within days of this revision, which reads as active work. It is not — the last human commits are from mid-2025. Those timestamps are the base branch moving and mergeability being recomputed.
Five of the seven are drafts with literally no review activity — no reviews, no inline comments, no conversation. That is correct behaviour on a draft; nobody reviews work marked not-ready. But it means the blockage on those five is authorship: they were never submitted, and they have sat since their author's last commit in mid-2025.
#6295 is not abandoned — it was adopted, and the adoption is now delivering
The one PR marked ready for review has a live thread. After a conflict notice (July 2025) and a technical objection from a maintainer who preferred native Turbo behaviour over a new library dependency (August 2025), a different contributor stepped in observed:
forkata · 2026-06-30
I am thinking of taking a stab at getting this PR updated so we can merge it. I wanted to check with you if you are actively working on this…
tvdeyen · 2026-07-01
sure, go ahead. I am not actively working on this. Still not happy with a library that we don't need, but also not fighting over it. One last try, though: it is not that hard 😉
forkata · 2026-07-06
Sounds great, I'll see if I can remove the dependency and get the same behaviour with native Turbo functionality!
That is a healthy community doing something difficult well: a maintainer conceding a design argument rather than blocking on it, and a contributor volunteering to adopt someone else's stalled work while accepting the reviewer's preferred approach. And the promise was kept: on 30 July 2026 forkata opened #6528Admin confirm modal without external dependency — the adoption, delivered as a fresh PR — "Admin confirm modal without external dependency" — the same feature rebuilt the way the reviewer wanted it observed. The project has a working mechanism for rescuing orphaned work, and it is running right now.
What it has not done is fire systematically. One of six orphaned pull requests found an adopter, a year after its author stopped. The other five sit untouched. PL5A departing contributor's work is adopted or closed within a release cycle is this mechanism, made routine.
So the corrected reading: the blockage is authorship rather than review capacity, but "abandoned" overstates it. The work was left in draft and went stale; the project's response mechanism works when someone invokes it by hand, and nobody has invoked it for the rest. Note what these seven cover — payment methods, tax rates, stores, option types, shipping methods — precisely the six list-only screens from Finding 2. The plan was coherent; the person carrying it stopped, and only one thread has since been picked up.
Incidental observation: a Copilot pull-request reviewer bot left a review on #6232shipping methods — draft in May 2025 observed. So some agent tooling already sits in the review path, even though nothing supports agent authoring (§07The Machine).
Why no alarm ever sounded
The architecture makes stopping halfway completely stable. Because the new admin depends on the old one and switches its own unfinished screens off, a half-built rewrite looks perfectly healthy from outside: tests pass, releases ship, no page 404s, no merchant sees an error. The system is built so that abandonment produces no symptom.
The most expensive initiative in the project's history stopped without a sound: three years and $45,760 in, the new admin is at version 0.4 — and the architecture makes abandonment produce no symptom.
What would it actually take to close the gap?
Worth sizing, because "three years and unfinished" implies a bigger remaining job than the code does.
The 132 existing components total 7,716 lines, covering roughly nineteen working screens. A list-only controller runs 30–36 lines with one or two component files observed. Extrapolating at the same density, the missing surface is on the order of 8,000–11,000 lines — meaningful, but not a moonshot.
A second, independent measure agrees. Because both admins are server-rendered, view templates are a fair proxy for screen surface: the old admin carries 277 ERB templates against the new admin's 111 observed. That puts the port at roughly 40% by template count — close to the 64% controller count only if you believe every controller is equal, which the findings above say they are not. Two different measures, both landing well short of the raw controller ratio.
| Work | Size | Nature |
|---|---|---|
| Add create/edit to six list-only screens | small | the code largely exists already, in five orphaned draft pull requests |
| Port ~15 straightforward screens (locales, themes, API keys, settings, images, properties) | medium | mechanical, highly delegable, agent-friendly |
| Port the returns and refunds workflow (7 controllers) | large | genuinely complex domain logic, not mechanical |
| Port variants, prices, taxons, stock movements | large | the heart of merchandising; deep interaction with core |
| Judge the order and product screens ready and turn the alpha switch on | judgment | no code — a decision nobody currently has standing to make |
| Remove the dependency on the old admin | separate project | only possible after everything above |
The honest answer: the remaining work is a few focused months for one person, or considerably less if the mechanical middle band is delegated to agents — but it is gated by two things money cannot buy.
First, the returns/refunds and merchandising work is real domain engineering, not porting. Second, and larger: someone has to hold this for two or three consecutive quarters. That is precisely the resource the project has been unable to supply since 2024, and it is why F2Built by one organization, handed to nobody rather than code volume is the binding constraint.
The sequencing was inverted, and it is the textbook failure
Will Larson's migration playbook — the standard reference on paying technical debt at scale — sets out three phases web:
- Derisk — "Write a design document and shop it with the teams that you believe will have the hardest time migrating." He warns explicitly against beginning with the easy cases, because doing so "creates a misleading sense of progress."
- Enable — build tooling to "programmatically migrate the easy ninety-percent."
- Finish — stop the bleeding, generate tracking tickets, and accept that the long tail requires the migration team to "dig into the nooks and crannies themselves."
Solidus's porting plan states the opposite strategy in its own words. Issue #5391the new admin's porting checklist — open since September 2023: "We want to tackle the easy pages first, so we can slowly improve and augment our UI kit components and then reuse it to migrate more complex pages (e.g. promotions)" observed.
The predicted failure is exactly the observed one. The easy settings pages were partially ported. Confidence ran ahead of reality — the Q2 2023 post reported that "the main components have been built, implementing the remaining sections will be easier and faster" web. And the hard core, where the domain complexity actually lives — returns, refunds, reimbursements, variants, prices, taxons — was never started at all.
Three years on, the project has a half-ported settings surface, an unticked checklist, and no evidence either way about whether its chosen architecture can express the difficult screens. That last part is the real cost of easy-first: after $45,760 and three years, the central technical question is still unanswered.
At rev 24 the Core Team answered this finding directly: partial concession on sequencing — "there's an argument to be made that we should have started with the hard stuff first, or at least got to it faster" — but a dispute on the stakes: "viability isn't a concern… I don't think anyone is worried that building them isn't possible. As the project is pre-1.0, churn isn't that big of a deal" stakeholder. An insider's confidence is a stakeholder judgment, not a ported returns screen — the question narrows from can it be built to what it will churn, and one hard screen is still the only evidence that settles it for an outside reader.
Did merchants reject it?
A reasonable theory, and the evidence does not support it. The open issues about the admin are overwhelmingly requests for missing features — "introduce taxonomy creation," "add product specifications," "edit product stock quantity," "enable creating option types" — the signature of incomplete, not disliked. Two usability tickets exist. The May 2025 status update was positive about the work observed web.
The one genuine point in favour: the alpha switch has been off for years, which is the team's own quality verdict. And private feedback in Slack is invisible to this audit, so the theory is not fully closed.
Spree, Measured
The competitor Solidus forked away from in 2015, which then died, and has now come back with money behind it. Figures from the GitHub API on 25 July 2026, with releases re-checked on 8 August.
One correction of the folk narrative, from the Core Team at rev 24: there never was a founding feud. After the split the projects collaborated directly for a while — especially on security issues that affected both — and the lines broke down later, with strategy shifts and the changeover in who ran this project. "The only real 'drama' is just that they use Solidus projects as case studies on the Spree site" stakeholder. The present tense, from the same voice at rev 25: "very different approaches," disagreement on licensing and technical strategy, and "no beef these days, though. Just different directions" stakeholder.
| Metric | Solidus | Spree |
|---|---|---|
| Commits in the last 52 weeks (GitHub's own series — the git log in §06The People counts 493 over the same window; the 5.5× ratio uses one instrument on both sides) | 400 | 2,190 — 5.5× |
| GitHub stars | 5,317 | 15,572 |
| Forks | 1,400 | 5,287 |
| Latest release | v4.7.0 · 15 Apr 2026 | v5.6.1 · 28 Jul 2026 |
| Platform releases in July 2026 | 6 | |
| Cumulative package downloads | 3.22M | 2.85M |
Feature comparison
| Capability | Solidus v4.7.0 | Spree v5.6 |
|---|---|---|
| REST API | yes | with OpenAPI specification |
| GraphQL | dormant since Oct 2023 | not offered |
| Admin interface | two — old one, plus v0.4 with main screens off | one, with a plugin system |
| Storefront | server-rendered Rails template, 64 spec files, installed by the generator | Next.js 16 / React 19 / TypeScript, separate repo |
| TypeScript SDK | no | three packages |
| Command-line tool | no | boot, generate, migrate, query the API |
| One-command project setup | multi-step manual install | npx create-spree-app — 1,607 downloads last month |
| Hosted trial | no | free sandbox, nothing to install |
| AI-agent harness | none | AGENTS.md, CLAUDE.md, committed agent settings, hooks, skills |
| Published agent skills | no | for "Claude Code, Cursor, Copilot and 60+ other tools" |
| Documentation MCP server | no | yes |
| Sales channels, stock reservations, order routing | no | free edition |
| B2B — price lists, approval workflows | no | paid Enterprise |
| Multi-vendor marketplace | no | paid Enterprise |
| Multi-tenant white-label | no | paid Enterprise |
| No JavaScript supply chain | zero npm dependencies | pnpm, Turborepo, 11 JS packages |
| Cannot be relicensed by anyone | BSD-3 throughout | Enterprise modules are commercial |
| Support | community Slack | community Slack · or paid SLAs, 24/7, dedicated manager |
Read the last three rows together. They are the only rows where Solidus wins, and they are not accidents — they are consequences of being what Spree stopped being.
What ‘better funded’ actually means
Spree's free edition includes the storefront, checkout, sales channels, stock reservations, order routing and the APIs. The Enterprise Edition adds three separately licensed commercial modules — marketplace, B2B, multi-tenant — plus a support tier with graded response-time guarantees, long-term support releases and 24/7 monitoring web. No pricing is published; one third-party estimate puts year-one licence and implementation in the five-to-six figures web.
Spree's free edition is a sales funnel for enterprise licences. Solidus's free edition is the entire product, with nothing behind it.
This is structural, not circumstantial. Spree's open-source work is a marketing and R&D cost carried on an enterprise profit-and-loss; Solidus's is carried on a donation pot taking in about $25k a year. A community-governed collective cannot replicate that model without ceasing to be one inferred.
Spree's open source is a marketing cost carried on a real business; Solidus's is carried on a $25k-a-year donation pot.
The harness gap deserves its own paragraph
Spree publishes AI-agent skills installable in one command, runs a documentation MCP server, and advertises its command-line tool as working "hands-free for AI agents." Internally it carries agent instruction files, committed permissions, hooks and version-locked skills observed web. Solidus has none of this — re-confirmed 8 August 2026: the repository root still carries no agent instruction file of any kind observed.
This is harness engineering used as product strategy: making the framework legible to AI agents is a distribution channel, because a growing share of new projects starts with a developer asking an agent to build one. Spree is contesting the channel where new stores now get started, and Solidus is not present in it.
Fair caveat: causation is unproven. Spree also has commercial funding, so the harness may be a symptom of resources rather than a cause of throughput. And one third-party article claims Spree's activity surge is "primarily driven by LLM-generated contributions" web — if true, that would qualify the 5.5× figure, since volume would not equal value.
But Spree did not cause Solidus's decline
Spree relaunched commercially in April 2025. Solidus's sponsor cancellations run 7 · 7 · 7 · 4 · 5 · 2 · 5 · 2 per year from 2019 — with 2024 and 2026 the two lowest years on record. There is no post-relaunch exodus. Nebulab's engineering had already collapsed in 2024, a full year before Spree 5.0 observed.
Solidus's decline is endogenous — long-run sponsor attrition, the loss of its steward, and a capacity collapse in mid-2025. Spree's resurgence is a separate, concurrent event. What it changes is not the cause but the options: it forecloses "we will catch up later."
The competitor in one line: Spree ships five and a half times Solidus's commit volume, six platform releases in July 2026 alone, and its free edition is the sales funnel for a paid enterprise product.
The Strategy Already in Force
Before proposing new strategy, it is worth writing down the strategy that already governs decisions — whether or not anyone wrote it down. There is always one. Proposals that contradict an unnamed rule get resisted by mechanisms nobody in the room can point to. Every policy in §02Policies & Operations names its relation to these rows for exactly that reason.
| # | The rule, as if it had been written down | Written? | Working? |
|---|---|---|---|
| S1 | Reject the JavaScript-framework direction on purpose. Simplicity, one stack, no fees, distributed governance. | on the lead maintainer's company blog | The project's actual strategy — stated, just not here |
| S2 | Never break an existing store. Deprecate before removing; back-port fixes to old versions. | ratified | Holding — at a cost nobody has priced |
| S3 | Ship replacements alongside the old version as opt-in, with a written migration guide; the old one stays until stores have moved. | in the gems, not the governance | Working — see the promotions migration guide |
| S4 | Core stays lean; capabilities live in separate extensions. | nowhere | Weakening — four official extensions dormant |
| S5 | Merge authority belongs to a self-appointing Core Team. Money buys votes on spending, never on code. | ratified | Yes — the separation is deliberate and healthy |
| S6 | Quality is enforced by machines; style is not argued about. | only in CI config | The best-functioning rule in the project |
| S7 | All delivery is done by humans. | by omission | Untested — no agent harness exists |
The strategy is written down — just not by the project
Solidus's technical direction is not unwritten, and it is easy to miss because of where it lives. The lead maintainer published it on 12 May 2026, in a post comparing Solidus and Spree web. Its stated pillars:
- Governance — "Spree is managed by a single company. Over the last two years, more than 90% of the commits to the project come from that company," against a Solidus core team "made up of representatives from a variety of different companies."
- Licensing — "Solidus remains completely free. No fees whatsoever. You own your eCommerce stack."
- Technical direction — the JavaScript-framework path is rejected deliberately: teams find "the increased complexity wasn't worth it," and "digital commerce businesses want simple and efficient solutions, not multiple web stacks."
- Philosophy — "stability, thoughtfulness, and control."
This report independently arrived at nearly the same positioning in §16Choose a Role. That convergence is reassuring about the analysis and unflattering about the finding: it was not a discovery. The strategy exists, is articulate, and is hosted on a consultancy's marketing blog rather than in the project's own artifacts.
That is the actual knowledge-debt finding — sharper and more fixable than "no strategy exists." Moving S1Reject the JavaScript-framework direction on purpose into a governing document costs one afternoon: E5Republish the strategy statement in the project's own artifacts in the fast lane, PL3Decisions are published where adopters can read them as the standing rule.
What else this table catches
- S3Ship replacements alongside the old version as opt-in, with a migration guide works better than the unfinished-migration count implies. The promotions gem ships a 190-line migration guide and an explicit "migrate at your earliest convenience" advisory. The discipline exists; what is missing is a scheduled removal date, not the practice. That is the amendment PL1Every replacement names the release that removes what it replaces makes.
- S2Never break an existing store — deprecate before removing is enforced by a machine, which is exactly right — a build gate rather than a good intention.
- S5Merge authority belongs to a self-appointing Core Team assigns the authority and stops there. It gives the Core Team final say over what goes into core, and the stakeholder group a weighted vote over money — then says nothing about when either body convenes on a technical question, what settles it, or where the answer is recorded. The admin has been neither shipped nor cancelled for three years inside a structure that plainly permits either. PL4Every parallel initiative gets a quarterly disposition adds the missing venue without moving the authority an inch.
The roadmap records the past and plans nothing
The May 2025 status update promised to "double-down on the existing GitHub project called Roadmap" for transparency. They did keep it alive — it was updated in June 2026. But of its 76 items, 65 are merged pull requests and 7 are closed issues. Exactly three open issues and one open pull request are forward-looking, and one of those three is a housekeeping item last touched in May 2025 observed.
It is a changelog wearing a roadmap's name. Not stale — actively maintained — but it documents what happened rather than stating what will happen. A prospective adopter checking whether Solidus has a future finds a well-kept record that it had a past.
This is the same failure mode as S1Reject the JavaScript-framework direction on purpose: the project does the work and does not state the intent.
Root Causes
Two mechanisms generate almost every symptom in this report, and they compound each other.
RC1 — Migrations are engineered but never scheduled
The project plainly can run a migration well. Promotions ships a 190-line guide covering data migration, behaviour switching, custom rules and legacy removal, plus an explicit advisory to migrate now. The storefront was absorbed cleanly in six weeks by four people from two organizations observed.
Nor is the fault an absence of plans. The admin has a published porting checklist with a sequencing rationale (#5391the new admin's porting checklist — open since September 2023, §08Admin Autopsy); promotions has a 190-line migration guide; there are milestones for 4.8 and 5.0. The artefacts exist and go untended.
But "assign an owner and a date" is the wrong prescription for a volunteer project, and it is worth being careful here. Nobody can be assigned a deadline they are not paid to meet. Unowned, undated work is the normal condition of volunteer open source, not a pathology — and treating it as a governance failure misreads the mode the project operates in.
The two stuck migrations need different things, and collapsing them obscures that:
- Promotions needs a policy statement, not capacity. The work is already done — a complete engine with 113 spec files and a 190-line migration guide. A removal date for the legacy engine ("Solidus 5.0 drops it") assigns nobody any labour; it is a commitment the project can simply make. Rails and Ruby both publish deprecation timelines this way. This one is genuinely free and has not been done.
- The admin needs paid capacity, and cannot be volunteered into existence. Twenty-seven missing screens including a returns workflow is not something an unowned checklist produces. It was never going to be, and expecting otherwise is the actual mistake in the record.
Which points at the real gap: nobody has been paid to do this since July 2025, and there is $133,750 to pay them with.
The project has funded development four separate times — a maintainer retainer in 2020, the admin push in 2023, contracted developers through 2024 and into 2025 (§04The Money). Each time the money bought motion. Since the last engagement ended, the balance has grown and nothing has moved on the admin.
So RC1Migrations are engineered but never scheduled is not "no calendar." It is an unfunded initiative sitting next to an unspent budget — and the artefacts look neglected because volunteers were left holding work that needed paying for.
Ensures: A migration can stall indefinitely without anyone noticing
RC2 — The steward changed in the code but not in the governance
Nebulab went from ~60% of commits to ~1%, with no public announcement observed web. Two symptoms filed separately elsewhere descend from this one fact: the admin rewrite stalled, and its pull requests were orphaned.
The fault is not the departure. Sponsors rotating out is normal, and Nebulab remains the largest cumulative funder. The fault is that the project has a mechanism to transfer money and none to transfer sponsorship of unfinished work. When a sponsor leaves, their bets are neither reassigned nor cancelled — they are orphaned in a state that rule S2Never break an existing store — deprecate before removing then preserves indefinitely.
And this is the second occurrence. Stembolt was acquired in 2018 and walked away too. The 2018 handover succeeded only because a willing successor happened to exist. The custody chain reads Stembolt → Nebulab → nobody inferred.
Losing the steward is not a shock this project suffered once; it is its normal condition, and in ten years the governance never grew a mechanism for handling it.
Ensures: That one of the stalled migrations is exactly what happens next
The two causes compound into a single condition: an unfunded initiative sitting next to an unspent budget.
Risk Register
Things that might happen, ranked by damage × likelihood × how likely you'd notice before it bites × cost to recover. That third factor is easy to miss: a quiet failure outranks a loud one of equal size, because nothing warns you.
R1 — Routine dependency drift between security releasesdowngraded
Narrower than a repository-only reading suggests. Solidus runs a HackerOne disclosure program, automated security dependency updates, an 18-month patch window across three supported versions, two mandatory reviews before merge, and multi-factor authentication on release accounts (§07The Machine) web. The path by which a known vulnerability reaches stores is well defended.
What remains is the gap around it: no automated routine version bumps and no bundler-audit step in the build, so ordinary dependency drift accumulates between security events and is caught only when someone looks observed. The fix is two configuration files — E2Renovate or Dependabot config for routine updates and E3A bundler-audit job in CI in the fast lane.
If it happens: Stale transitive dependencies age quietly; the exposure window before a disclosed issue is noticed widens
Likelihood: Low for disclosed vulnerabilities — that path is covered. Medium for drift
Would you notice? For a disclosed CVE, yes. For gradual drift, no
Cost: Moderate, not critical
What would change my mind: A Renovate or Dependabot version-update config landing, which would close this entirely
R2 — Two firms are 78% of the money and most of the codehard to detect
Code concentration and funding concentration are the same dependency seen from two sides. The largest individual contributor commits from a personal address with no organization behind him. One of the two firms now markets Shopify work at equal weight with Solidus observed web. No policy in this report addresses the concentration itself — that deferment is argued in §02Policies & Operations.
If it happens: Losing either firm removes ~39% of funding and a large share of throughput at once
Likelihood: Medium — this has already happened twice
Would you notice? Not for months. A departure looks exactly like a quiet quarter
Cost: High
What would change my mind: Six consecutive months where no single party exceeds 25% of merged commits
R3 — The half-built admin becomes a permanent third statehard to detect
Three years, version 0.4, 19 commits so far in 2026, both admins in every installation, and the architecture actively hides the problem. Rev 24, from the Core Team: the admin is alive and deliberately paced — real stores run it incomplete today, and work "will resume at pace once we have our new candidate in place" stakeholder. That is exactly the answer §22What I Could Not Establish said would move this risk from high to low, and it does — with one reservation: the drop rests on a stated intention, and only the falsifier closes the risk. The next outgoing ledger expense is the observable that confirms the candidate, and as of 8 August 2026 it has not appeared — the ledger's last debit is still July 2025 observed. At rev 25 the intention gained a second leg: "The Admin is a priority," and the candidate model is deliberate — independent devs funded from the collective while the maintaining firm stays on client work stakeholder. The stated intention stands; at the 8 August re-check, five days after it gained its second leg, the confirming evidence had still not appeared.
If it happens: The primary evaluation surface for new adopters stays broken, and the maintenance bill doubles indefinitely
Likelihood: Lowered at rev 24 — deliberately paced by the Core Team's account; the confirming observable has not fired yet
Would you notice? No. Every signal a maintainer looks at is green
Cost: High and rising as the old admin ages
What would change my mind: Version 1.0 becoming the default — or a recorded decision to cancel it
R4 — Spree takes the new-project marketeasy to see coming
Measured in §09Spree, Measured. Note this ranks below R1Routine dependency drift between security releases–R3The half-built admin becomes a permanent third state despite high impact, precisely because it is loud and public — the project will see it happening. What I cannot establish is whether merchants are actually switching: cumulative downloads still favour Solidus, and per-release download rates are distorted by Spree's faster release cadence observed.
R5 — The new storefront breaks existing extensions by design
Its own README states that extensions relying on the old storefront "will not work with this storefront." Impact medium, likelihood certain — a stated property rather than a hazard observed.
If only three can be addressed
R3The half-built admin becomes a permanent third state., then R2Two firms are 78% of the money and most of the code., then R4Spree takes the new-project market.. R3 is the largest live misallocation of capital and attention, and it is invisible from inside. R2 is slow and structural, but it is the mechanism that produced R3, so leaving it guarantees a recurrence. R4 is third because although it is highly visible — which normally lowers priority — the measured gap is now large enough that visibility stops being much comfort.
R1Routine dependency drift between security releases. has moved out of the top three. An earlier ranking placed it first on the strength of a repository-only reading; the published security policy shows the serious paths are covered, and what remains is routine drift worth a configuration file, not a quarter's attention.
R5The new storefront breaks existing extensions by design. waits because it is known, bounded and has an obvious mitigation whenever someone wants it.
- R3The new admin stays stalled — placed high because the silence is the finding
- R2Contributor concentration — one organization's withdrawal already proved the shape
- R4Spree competition compounds while Solidus stands still
- R5Extension breakage on major upgrades
- R1Routine dependency drift between security releases
Debt Ledger
Distinct from risks. A risk might happen; a debt is a cost already being paid, every single release. Ranked by cost per cycle multiplied by how many future cycles will pay it.
D1 — Three unfinished rewritesstrategic
Every change to promotions, admin or storefront behaviour is designed twice, written twice, tested twice and released twice. There is no scheduled end. This is the largest recurring cost in the project — and it is invisible on every dashboard the project has, because both halves are green. PL1Every replacement names the release that removes what it replaces and PL4Every parallel initiative gets a quarterly disposition are the standing rules that stop the ledger growing a fourth entry of this kind.
D2 — Governance describes a project that no longer existsorganizational
Entry to the Core Team runs through one person's private messages; technical authority is assigned but has no published venue, cadence or record; and no decision reaches a public artefact. Paid in every evaluation a prospective adopter makes, and every contributor who cannot find the door.
D3 — Architectural decisions are never recordedknowledge
No architecture document, no decision records, roadmap repository dormant since May 2023. Decisions live in a weekly call and in Slack. Every migration re-derives context that was never written down — and rule S3Ship replacements alongside the old version as opt-in, with a migration guide, which governs all three of them, exists only in people's heads.
D4 — The agent harness, and two small automation gapstechnical
The substantive item is the absent AI-agent harness. Alongside it sit two minor gaps: routine dependency-update automation and an audit step in the build — both narrower than they first appear, since automated security updates already run and a full disclosure programme sits behind them (§07The Machine).
Priced at what these cost with agent assistance today, all three together are roughly a day of work — the repository already has Docker Compose, a setup script and a one-command test loop, which is most of the prerequisite. Any past decision to defer these was made at pre-agent prices and is now stale. All three now sit in the fast lane as E2Renovate or Dependabot config, E3A bundler-audit job in CI and E4An in-repo agent harness, where they no longer compete with the difficult decisions for attention.
Credit Ledger
The asset side. What has been built that pays back every cycle — and what was claimed as an investment but has not paid back yet. An investment counts as real only once something actually reuses it.
Confirmed — reuse has actually happened
C1 — Test matrix current to the newest Rails and Ruby
Every pull request runs it; Rails 8.1 and Ruby 4.0 entered the matrix within weeks of their releases.
C2 — Deprecation build gate
This is what makes the upgrade promise credible rather than aspirational.
C3 — Automated back-porting
Five maintained release lines carried without manual work.
C4 — Automated code style
Style debate removed from every review since v4.7.0.
C5 — Release and changelog automation
Every release generated from labels.
C6 — Reproducible development environment
Used by every contributor — and most of an agent harness already.
C7 — The storefront
64 spec files installed into every generated store, exercised end-to-end by CI on every push, and the generator's default frontend.
Projected — claimed, not yet realized
C8 — solidus_promotionsoverdue
2 years 2 months in. The beneficiary would be the default installation.
C9 — solidus_adminpast the point of write-off
3 years 3 months in, still version 0.4.
That asymmetry has an explanation, and it is the key to the whole report
Volunteer effort sustains the parts that automate. It does not sustain the parts that need sustained human attention.
Continuous integration, linting, back-ports and release automation each need attention once and then run by themselves forever. Finishing an admin, porting 27 screens, shipping a storefront — these need someone to care for four consecutive quarters. Solidus's model works precisely where automation works and fails precisely where it does not.
This is also why "the community loves it" is entirely compatible with $133,750 nobody spends and 78% of funding from two firms. Affection produced an excellent machine and no successor.
Who Solidus Can Still Serve
Given everything above, the honest question is not "how does Solidus recover" but "who is left that it can genuinely serve well." Three candidate audiences, tested against the evidence.
A new merchant who wants a storefront quickly (not viable)
Spree: npx create-spree-app my-store, or a hosted sandbox with nothing to install. Five minutes.
Solidus, from its own documentation: create a Rails app, add the gem, hand-write an asset manifest file, run a generator, and possibly hand-build the CSS because "this issue typically occurs when you bundle from a branch." Then arrive in an admin that cannot open an order observed.
Not viable without an agency — which has always been true. Solidus was agency-mediated from birth.
A solo developer who likes classic open source (weakest of the three)
Tempting, but the evidence points the other way. A solo developer is precisely the person who needs the scaffolder, the CLI, the hosted trial and a working admin — the exact list Solidus lacks.
More decisively, the project's own largest contributor publicly disclaims this segment. Jared Norman's How to Fail at Solidus (Nov 2024) states that Solidus suits high-volume stores, large catalogs and marketplaces — not simple small shops web. When your leading maintainer says a segment is a mis-fit, it is not your fallback.
An established merchant leaving a fee-taking platform (the real one)
The only segment where Solidus's remaining advantages are decisive rather than sentimental:
- BSD-3 with no commercial entity that could ever relicense it. Spree cannot say this — its Enterprise modules are commercial and its roadmap answers to investors. After Redis, HashiCorp and Terraform, this is a live concern, not a theoretical one.
- No JavaScript supply chain, one runtime. Less to operate and less to audit — permanently.
- Upgrade safety with real teeth — a build gate and five maintained release lines, not a promise.
The fit: mid-market, heavily customized, existing or hireable Rails capability, long time horizon, re-platforming away from something and determined never to do it again.
Notice what segment three describes: the merchants Solidus already has. Its addressable market is people who look like its current customers. That is not a growth strategy — it is a stewardship strategy, and it is the honest one.
Choose a Role
The instinctive question is "how does Solidus recover?" On the evidence assembled here, that is the wrong question — the project cannot fund a fight for new merchants. The right question is which role it deliberately chooses. All three below are legitimate; drifting between them is not.
The conclusion this evidence supports is a role, not a comeback: the commerce framework you can still own in ten years, serving the merchants who already chose it.
Role A — Steward the installed base
Declare it openly: no new initiatives. Guarantee upgrade safety, security patches and current Rails/Ruby support. Finish the promotions migration because it is nearly done. Cancel the new admin and the new storefront.
For: honest, matches a $25k-a-year budget, monetizes the one advantage that is real, and immediately retires the largest recurring cost in the Debt Ledger. Against: it is an explicit acceptance of managed decline, and some contributors will leave over it.
Role B — Contest the agent channel
The one place a small budget could still buy asymmetry. A single-runtime Rails framework is genuinely easier for an AI agent to work in than a Rails-plus-Next.js-plus-TypeScript monorepo: one dependency graph, one test command, no context switching across a language boundary. The cost is a harness, not a rewrite.
A second-order argument worth stating, because it cuts against the obvious objection: agent competence tracks how much of a stack appears in training data, which favours React and Next.js. But agent reliability tracks convention density — how few defensible ways there are to do a given thing — and Rails with Turbo and Stimulus is far more opinionated than React. Corpus size favours Spree; convention density favours Solidus. These substantially cancel.
The pitch: "One codebase, one language, one test command, no JavaScript supply chain to audit. Your agent works in Rails, not across a monorepo boundary." Spree structurally cannot say this — their entire 5.x strategy is the opposite bet.
Two harnesses, not one. The project needs one for its own contributors — that half is now a fast-lane item, E4An in-repo agent harness, because it costs about a day. The more valuable half is the one store builders need for their applications. Solidus already invests seriously in developer tooling for the people who build on it: solidus_dev_support, a published GitHub Action for testing extensions, the edge guides. Jared Norman's own advice is "leverage the platform… Solidus ships with great support for testing, CI, CD." An agent harness is the 2026 member of exactly that family, and it is the one item missing from a set the project already believes in. The store-builder half is judgment-gated on the role choice, which is why it stays out of the fast lane.
Spree has already shipped the store-builder half — one-command installable skills targeting Claude Code, Cursor and Copilot. The asymmetry Solidus can still claim is not being first; it is that a single-runtime Rails store is a smaller, cleaner thing for an agent to reason about than a Rails-plus-Next.js monorepo.
Role C — Converge with Spree
Unpalatable, which is exactly why a strategy document should name it. The fork's founding justification — that Spree was abandoned — died when Spree came back. Both are BSD-3. One of them has funding and a maintained admin.
Nobody inside the project will propose this. That is not a reason to leave it unwritten.
| Role | The move | The catch |
|---|---|---|
| A — Steward the installed base | No new initiatives; guarantee upgrades and security; finish promotions; cancel the admin and storefront | An explicit acceptance of managed decline — some contributors will leave |
| B — Contest the agent channel | Ship the missing agent harness; sell "one runtime, one test command" to agent-driven builders | Spree shipped theirs first — a modifier on Role A, not an alternative |
| C — Converge with Spree | Fold back into the project Solidus forked from | Nobody inside will propose it, which is exactly why it must be written down |
Red-teaming Role B, because it is the tempting one
Spree has already published agent skills and a documentation MCP server. Being second to the harness with a twentieth of the money is not obviously winnable, and an agent's familiarity with React may beat an agent's ease of navigating Rails. The asymmetry is thinner than it first appears.
It remains the cheapest bet on the board — but it is a differentiator, not a rescue. Role BContest the agent channel is a modifier on Role ASteward the installed base, not an alternative to it.
Positioning, if Role A or A+B is chosen
The current public tagline is "A free, open-source e-commerce platform that gives you complete control over your store." The "complete control" half is a stronger claim in 2026 than it was in 2015. The "platform" half is currently unearned — a platform whose admin cannot open an order is a construction site with a promise attached.
The commerce framework you can still own in ten years.
That is a stewardship promise rather than a feature promise, and it is the one claim in this entire comparison that Spree structurally cannot make and Shopify would never want to.
Easy Wins
The fast lane, new at rev 26. These items pass three gates — about a day of agent-assisted work or less, delegable and reversible, and each feeds the delivery machine directly — so they run alongside the strategy rather than inside it. They never occupy a cut slot, and the argument over the difficult bets below never cites them. Two former bets moved here: B3 became E2Renovate or Dependabot config and E3A bundler-audit job in CI; B4's in-repo half became E4An in-repo agent harness. An entry that blows its day or turns out to need judgment gets ejected back to the bets table, with whatever resisted named.
| # | Win | Feeds the machine | Agent-day | Status |
|---|---|---|---|---|
| E1 | Tick the boxes on #5391the new admin's porting checklist — open since September 2023 that the code shows are already done — Settings > Zones has had full CRUD for some time. A checklist nobody updates says the work stopped; the same checklist current says it did not. Re-confirmed still unticked on 8 Aug 2026 observed. | knowledge | minutes | — |
| E2 | A Renovate or Dependabot config for routine version bumps. Security updates already run; this closes the drift gap that keeps R1Routine dependency drift between security releases on the register. (Formerly bet B3.) | dependency hygiene | an hour | — |
| E3 | A bundler-audit job in CI, so known-vulnerable dependency versions fail the build instead of waiting for someone to look. | static gates | an hour | — |
| E4 | AGENTS.md/CLAUDE.md plus committed agent permissions, on top of the Docker Compose setup, bin/setup and one-command test loop that already exist — most of a harness is already there. First jobs: execute E2Renovate or Dependabot config and B5Name the release that removes legacy promotions. (Formerly bet B4's in-repo half; the store-builder half is judgment-gated on Role B and stays with the bets.) | agent harness | ~a day | — |
| E5 | Republish the strategy statement — the four pillars the lead maintainer already wrote in May 2026 — in the project's own README or governance document, so S1Reject the JavaScript-framework direction on purpose stops living on a consultancy's marketing blog. Also the cheapest first act of PL3Decisions are published where adopters can read them. | knowledge | an hour | — |
Bets — for you to set
Scored against Role ASteward the installed base+B, since that is where the evidence points. Deliberately left as a starting position rather than a finished plan — the role choice in §16Choose a Role is a judgment call, and these should be re-scored against whichever role is actually chosen. The trivial items are gone from this table by design: they live in §17Easy Wins now, so what remains here is only the decisions that need an owner's judgment.
B10 — the cheapest bet on the board
The Core Team already holds technical authority. The stakeholder group already meets weekly. The project already owns two channels built to carry public direction — a roadmap board and a blog. Nothing needs to be created; two dormant things need restarting. The blog has even stirred on its own: one release announcement in May 2026, then quiet again web.
What it fixes: a prospective adopter evaluating Solidus today finds a roadmap of completed work and a blog that speaks once or twice a year, and cannot tell whether the platform has a future. That is not a governance problem — the decisions may well be getting made. It is a publication problem, and it costs an hour a month.
It also resolves the S1Reject the JavaScript-framework direction on purpose finding cheaply. The project's clearest statement of strategy currently lives on a consultancy's marketing blog; the same words on the project's own blog make it the project's position rather than one firm's opinion.
Do it as: a short monthly post naming decisions taken and deferred, plus forward-looking items on the roadmap board — which currently has three, one of them untouched since May 2025. The five-minute opener is E1Tick the already-done boxes on the porting checklist.
Decision Template — B9, dual asset-pipeline support
The most concrete bet on the board, and the only one that pays into five separate findings at once. Written up in full because it is ready to be accepted or rejected as stated.
Decision
Support both asset pipelines in Solidus. New installations default to Propshaft and may opt out to Sprockets. Existing stores keep Sprockets and opt in to Propshaft when ready. Ship an agent skill that performs the migration on a customer's store and verifies it by booting the app and running the suite.
Context
Rails 8 defaults to Propshaft. Solidus core hard-requires Sprockets, whose maintaining gem has not shipped since July 2024 and whose relevant fix has been unmerged for 18 months. That pin is the documented cause of the project's longest-running bug class, and CI currently stays green only by performing an undocumented workaround step (§07The Machine).
Why this shape
It matches the strategy already in force. Rule S2Never break an existing store — deprecate before removing forbids breaking existing stores; rule S3Ship replacements alongside the old version as opt-in, with a migration guide ships replacements as opt-in alongside the incumbent. This is the promotions pattern applied to the asset pipeline — a bet that contradicts no strategy-in-force and therefore meets no unnamed resistance.
Alternatives
(a) Wait for upstream — unavailable; the fix is unmerged in a dormant gem. (b) Hard cutover to Propshaft — violates S2Never break an existing store — deprecate before removing and breaks every existing store's asset setup. (c) Stay on Sprockets — the status quo; costs the Rails-currency claim, the onboarding path, and eventually forces an emergency migration when Rails drops support. (d) Migrate only when the new admin lands — couples this to the one decision that has resisted resolution for three years.
The gate, and how it is cleared
The old admin carries 151 Sprockets directives and cannot run on Propshaft as written, so defaulting new installs to Propshaft appears to depend on retiring it. Sidestep: precompile the old admin's frozen assets once and ship them as static files. Propshaft serves static assets fine. This decouples B9Dual asset-pipeline support, with an agent-executed migration from the admin question entirely, and reuses the pattern that made the storefront succeed.
Risks reduced
Closes the failure class behind issues #6327installer fails with a Sprockets error, #5410the new admin breaks asset compilation when the host app has Tailwind and #6516align the install instructions with the storefront. Removes a dependency on an unmaintained gem from a payments framework. Ends the divergence between the tested install path and the documented one. Closes the Rails-generation gap in §07The Machine.
Risks introduced
The serious one: a fourth dual-support burden in a project whose largest recurring cost (D1Three unfinished rewrites — the largest recurring cost in the project) is already paying for everything twice. Both pipelines need CI coverage, doubling that matrix. Secondary: precompiled admin assets become a build artifact someone must remember to regenerate if the legacy admin is ever touched.
The condition that makes it acceptable
It ships with a deprecation date or it does not ship. Root cause RC1Migrations are engineered but never scheduled is that this project engineers migrations well and never schedules them. Name the major version that removes Sprockets support, put it in the gem README beside the promotions advisory, and add it to the roadmap board as a forward-looking item. This is PL1Every replacement names the release that removes what it replaces applied at birth rather than retrofitted.
Cost
Core: shallow — one conditional require and one ERB removal. New admin: already compatible. Old admin: a one-time asset precompilation. The agent skill: the mechanical, well-specified class of work the framework prices in agent wall-clock rather than developer-days.
Credit produced
The agent skill is the reusable asset, not the pipeline change. Its named first reuse is the promotions migration — which has had an excellent 190-line guide for two years and has moved approximately nobody. A guide is advisory; a skill is executable. If the skill shape works here, it is the delivery mechanism for every future opt-in migration this project ships.
Refinement
The narrowest useful slice: the agent skill migrates one reference store to Propshaft and proves it by booting the app and running the generated suite — before any default changes. The rollout needs no separate formal test beyond that, because the change is opt-in and reversible: the opt-in period itself is the test of the stricter future version, the flipped default. If the skill cannot migrate the reference store cleanly, the bet stops there, having cost one store's worth of work.
Accepted by
Core Team, who hold explicit final say over what goes into core. The authority is unambiguous; what is undefined is when they convene on it and where the decision is recorded (§06The People) — so this bet should be accepted somewhere publicly visible, which is itself the point of PL3Decisions are published where adopters can read them.
Executed by
A deterministic check — the strongest kind of enforcement, ahead of written norms and reminders: CI runs the documented install path, from released gems, on both pipelines. Documentation drift then fails the build rather than reaching a user.
Success criteria — controllable
Dual support merged · new installs default to Propshaft · the manifest.js workaround deleted from both CI and the docs · #6516align the install instructions with the storefront closed · the agent skill migrates a reference store to green · a deprecation version named in writing.
Signals to report but not gate on
How many existing stores actually migrate. That depends on their appetite, not on the project's execution.
Exit strategy
If dual support proves too costly to carry, the fallback is Sprockets-only plus a documented, agent-assisted escape hatch for stores that want Propshaft — losing the default but keeping the migration path.
Falsifier
The skill ships and, twelve months later, migrated stores are as rare as promotions migrations are today. That would prove the constraint was never the difficulty of migrating but the absence of a reason to — which would put the whole "keep the Rails-way edge" thesis in question, not the tooling.
Review date
2027-01-25, or the first major release after merge, whichever comes first.
Red-team of B9
The honest case against: this is a developer-experience bet in a report that concluded the viable audience is existing merchants who onboarded years ago (§15Who Solidus Can Still Serve). Those merchants do not care which asset pipeline their agency uses.
The case survives, but on narrower grounds than "onboarding." Its real value is removing an unmaintained dependency from a payments framework, restoring the coherence of the Rails-currency claim that §16Choose a Role's positioning rests on, and proving the agent-skill delivery mechanism on a small, verifiable migration before betting the promotions cutover on it. Framed as onboarding, it is a nice-to-have. Framed as de-risking a dead dependency and rehearsing a delivery mechanism, it is the strongest item in this table.
B6 — how to make a three-year-old decision answerable
"Fund it or cancel it" is a judgment nobody has been able to make, and asking again will not help. The way out is to run the cheapest possible step that produces the missing evidence — which is also, not coincidentally, the first phase of the standard migration playbook the project skipped. In the framework's terms, B6 is the refinement slice for the admin: the narrowest, deepest test that tells you whether the strategy's mechanics work before anyone commits to a rollout.
Step 1 — Derisk — port the hardest screen first, by hand
Not Zones. The returns and refunds workflow, or variants and prices. These are where the domain complexity lives and the only place that answers the question three years of settings pages did not: can this architecture express the difficult screens at all?
This is the step Larson puts first and Solidus put last. Done by someone senior, it costs one screen and settles the entire funding question — because if the ViewComponent and Turbo patterns handle a returns flow cleanly, the rest is mechanical; and if they do not, no amount of funding fixes it and the correct answer is to park the admin.
Pay for it. This is not volunteer work and should not be waiting on someone's evenings — it is the highest-value engineering question in the project, and the collective holds $133,750 that has bought exactly this kind of work four times before (§04The Money). One funded screen is the cheapest possible use of that balance, and unlike the 2023 round it buys an answer rather than a sprint count.
Step 2 — Enable — encode the pattern as an agent skill
Solidus is unusually well-placed for this. 132 existing components already establish the house style, and the five orphaned draft pull requests are worked examples of precisely the CRUD-completion pattern a skill would need to learn (§08Admin Autopsy). The teaching material is written; nobody has compiled it.
There is also a proven manual precedent to automate. A contributor adopted one stalled admin PR, agreed the reviewer's preferred approach, and delivered the rebuild as a fresh pull request on 30 July 2026 (§08Admin Autopsy). That is exactly the loop — pick up orphaned work, conform it to house style, land it — repeated five more times. The community demonstrated the process by hand; a skill is that process made repeatable.
This is also where B9Dual asset-pipeline support, with an agent-executed migration's agent-skill machinery pays a second time — the same delivery mechanism, applied to a second migration.
Step 3 — Mass-migrate the mechanical band
The ~15 straightforward screens — locales, themes, API keys, settings, images, properties — plus create/edit on the six list-only controllers. This is the "delegable, parallelizable, well-specified" class the framework prices in agent wall-clock under fan-out, not developer-days. Pre-agent estimates for this band are stale by roughly an order of magnitude.
Step 4 — Finish — the nooks and crannies
Hand-complete the residue, tick #5391the new admin's porting checklist — open since September 2023's boxes as they land, flip the alpha flag once orders and products are judged ready, and treat removing the solidus_backend dependency as its own subsequent project.
What makes this the right shape
It converts a decision nobody can make into an experiment anybody can run. One hard screen tells you whether the remaining port is a few agent-weeks or a rewrite wearing a port's clothing. Either answer is actionable; the current state — three years of not knowing — is the only outcome that is not.
Falsifier for the whole plan: step 1 is done and the returns workflow cannot be expressed cleanly in the new admin's patterns. That would mean the architecture, not the funding or the ownership, is the binding constraint — and the correct response becomes cancelling the admin rather than resourcing it. That is a result worth $45,760 of hindsight and one screen of foresight.
The sequencing argument
B6Decide the admin — by manufacturing the evidence and B10Publish technical decisions — restart the status posts are judgment calls that cost almost nothing and unblock everything downstream. No amount of tooling substitutes for them, and AI assistance does not compress them — they are decisions, not tasks. Everything after them is delegable work whose pre-agent cost estimates are stale by an order of magnitude, and the truly trivial items have already been moved out of the argument entirely, into §17Easy Wins.
Sequencing the decisions first and the tasks second is the whole point. A plan whose milestones are task completions would hide the fact that this project stalls at decisions, not at code.
B2, stated precisely
This is not "hold a vote to spend the unused balance." The funding mechanism is well used — 67 expenses, $154,612, and $45,760 aimed at this exact problem in 2023.
The bet is not whether to spend but how to shape the purchase. Fund a named migration reaching default status — not sprints, not hours, not design phases. Name an owner who remains after the money stops. Set a target release. PL2Collective money buys named outcomes, not time is this bet generalized into the standing rule.
And note the falsifier is already half-observed: money was allocated in 2023 and the migration still did not ship. Money alone is demonstrably insufficient here. What remains untested is money tied to a completion criterion. If a second, outcome-shaped round also fails, the constraint is attention and authority, not funding — and the right answer becomes cancelling the admin rather than funding it.
Sequence
The moves in one line: none of the first steps is expensive — publish the decisions being made, name the release that removes legacy promotions, and fund outcomes rather than sprints.
Pre-Mortem
Not how the system fails — how this plan fails. Imagine it is a year from now and nothing changed. Why?
P1 — The hard screen gets deferred for an easy onemost likely
Step 1 of B6Decide the admin — by manufacturing the evidence asks someone senior to spend real time on the returns workflow with no guarantee of a shippable result. The path of least resistance is to port another settings page instead — which is exactly the decision that produced the current situation, and it will feel like progress again.
Early warning: The first screen attempted is one already on the #5391 checklist
Mitigation: Name the screen before starting, in public, and treat “we learned it does not work” as a successful outcome rather than a failed sprint
P2 — Nobody puts the funding decision on an agenda
Proposing it implies criticizing the status quo of people you see every week.
Early warning: Two stakeholder meetings pass with no agenda item
Mitigation: Send it as a one-page multiple-choice ballot over the three migrations — easier to table than an argument
P3 — The harness gets built and nobody uses it
Merge authority sits with a small group who have established workflows. A harness nobody adopts is a rounding error that looks like progress.
Early warning: No pull request references it within two release cycles
Mitigation: Scope it narrowly to E2 and B5. If those land, it paid for itself regardless of wider adoption
P4 — The funded migration is chosen by money, not readiness
Contribution-weighted voting could select the admin — largest, most stalled, most expensive — over promotions, which has the smallest remaining gap and full test coverage.
Early warning: A single-choice ballot
Mitigation: Multiple choice, producing a ranked list
P5 — The diagnosis is wrong and the constraint is attention, not moneypartly observed already
This one is not hypothetical: $45,760 was allocated in 2023 and the admin still is not the default three years later. The experiment ran once and failed.
What survives is narrower — money without a completion criterion does not ship a migration here. Money with one is untested.
Early warning: A second, outcome-shaped funding round also fails to ship
Mitigation: If money tied to a completion criterion fails too, cancel the admin
And one for the new layer: the register gets politely filed
The policy register is the part of this report most likely to die of courtesy. Five proposed rules arriving from outside, none urgent on any given day, all easy to thank and shelve — the same dynamic as P2Nobody puts the funding decision on an agenda, applied to paper instead of money. The early warning: two quarters pass and no PL row has been accepted, amended or rejected. The mitigation is built into the rows themselves: each one is small enough to decide in a single meeting, and PL4Every parallel initiative gets a quarterly disposition can be trialled once without accepting anything — run one disposition pass and see whether it was worth an agenda item.
Decision Log
What this report decided, and — more usefully — what it got wrong and corrected. Struck-through entries were superseded by later evidence.
Treat this as an existing-system audit, with single-decision depth on the admin question. (Accepted)
Open with agent-harness engineering, on the grounds that no deliberate strategy exists.
A deliberate strategy does exist — compatibility, merge authority and machine-enforced quality are all real, enforced rules. The harness was demoted below the two judgment calls and re-scoped as their executor
Report “no security policy for a payments framework” as a risk.
The policy exists at organization level and was found by widening the search
File the governance/reality mismatch as a debt, not a risk. (Accepted — it is already true, so it is a cost being paid, not an event that might occur)
Frame the $132,180 balance as capital nobody has a mechanism to spend.
67 expenses totalling $154,612 say the mechanism works and was already aimed at this problem. The bet became "shape the purchase," not "make the purchase"
Cite “$26,322 annual budget” and “$287,359 raised” from the rendered donation page.
Corrected against the API — $329,677 received, $154,612 spent, and the "budget" figure is simply trailing-twelve-month income
The stalled 2025 admin work is finished and blocked at review; reviewer capacity is the bottleneck.
Wrong. Six of seven pull requests are drafts never submitted for review, and all but one carry conflicts. The bottleneck is authorship. Diagnosis moved from "no venue" to "the people left"
Report the new admin as “64% complete by controller count.”
Misleading — order and product editing are switched off, six controllers are list-only, and the 27 missing screens are the daily-operations core
Describe Solidus as paying polyglot costs, citing 246 JavaScript files.
Wrong measure. There is no package.json, no lockfile and no npm graph. jQuery and Hotwire are the Rails-native style, not a second runtime. The single-runtime advantage is real and is now load-bearing in §16Choose a Role
“Thirty-plus sponsors have cancelled, so the base rate is not hypothetical.”
Count correct, implication wrong — it reads as a recent exodus. It is six years of steady attrition, and 2024 and 2026 are the lowest years on record
Reject the theory that Nebulab's sponsorship was a play for voting power. (The two top sponsors are tied under a cap neither has maxed, votes confer no code authority, and the economics run $44k negative. Marketing position is the better explanation)
Decline to characterize the Nebulab payments as extraction. (Net contribution is +$44,331, two claims were rejected, and an independent host reviews payments. The defensible finding is an insider payment with no completion criterion)
Reject "Spree caused the decline." (Cancellations are steady from 2019 with no post-relaunch spike. This reinforces killing B7Match Spree's React storefront — kill — matching a competitor that is not the cause is the losing move)
Decline to claim new merchants are choosing Spree over Solidus. (Not measurable from public data. The capability gap is proven; the adoption claim is not)
Reframe the report from "how to recover" to "choose a role." (Accepted — the evidence does not support a recovery thesis, and presenting one would be the more comfortable answer rather than the true one)
“Three unfinished rewrites” as a systemic pattern, generating root cause RC1.
Over-generalized from one case. Promotions ships a 190-line migration guide and a migrate-now advisory; the storefront was absorbed successfully in six weeks. Only the admin stalled. RC1Migrations are engineered but never scheduled narrowed from "no completion gate" to "no calendar"
Treat the project's technical direction as unwritten and derive it.
It is written — the lead maintainer published it on 12 May 2026. This report independently reconstructed nearly the same position, which validates the analysis and demotes the finding. The real debt is that the strategy lives on a consultancy blog rather than in the project's own artifacts
Treat the governance document's description of Nebulab's role as a finding at all (the governance-title strategy row, its bet, and its pre-mortem entry).
Vector removed entirely. "Director" covers business and organizational direction, which this audit has no visibility into; inferring anything about governance from a commit count was thin and uncharitable. Nebulab may well remain the project's principal steering figure regardless of who writes the code. The engineering handover finding (RC2The steward changed in the code but not in the governance, F2Built by one organization, handed to nobody) stands on its own evidence and is unaffected
Read the 40 open pull requests as evidence of review neglect.
Partly external. A job board was setting candidates Solidus issues as a screening task; the maintainer diagnosed it and intervened with the job board to stop it at source. That is active stewardship, not decay
RC1: “the gates were built; nobody is accountable for closing them, and no calendar says when.”
Wrong prescription for the mode. Unowned, undated work is the normal condition of volunteer open source — nobody can be assigned a deadline they are not paid to meet. Split into two: promotions needs only a policy statement (name the release that drops the legacy engine — free, and the work is already done), while the admin needs paid capacity and was never going to arrive by volunteer effort. Restated as: an unfunded initiative sitting next to an unspent budget. B5Name the release that removes legacy promotions reframed from "make it the default" to "name the removal release"
All seven stalled admin PRs characterized from API metadata: “the author never returned,” “reviewers engaged wherever they were asked.”
Metadata was misleading; the threads say more. Five chaimann drafts have zero review activity of any kind. #6232shipping methods — draft is by a different author and was properly reviewed. And #6295confirmation dialog — adopted by another contributor, July 2026 was adopted by another contributor on 2026-06-30 — three weeks before this audit — with the maintainer conceding a design argument rather than blocking. "Abandoned" overstates it: the project's rescue mechanism works and fired once, but not systematically. Also: reported "updated today" timestamps on two drafts are base-branch recomputation, not human activity. And a Copilot reviewer bot is already in the review path
“Differentiated code ownership ✗ — CODEOWNERS is a single catch-all line.”
Wrong twice. The file exists and works, so marking it absent was incorrect; and granular ownership would be the wrong design here — with three parties writing 83% of the code and departures as the defining failure mode, naming individual owners converts every exit into a stalled queue. The catch-all is plausibly the mechanism behind the policy's mandatory core-team reviews. Listed because CODEOWNERS sits on a standing checklist, not because evidence suggested a problem. Resolved in passing: pull-request and issue templates do exist, inherited from the organization — closing a §22What I Could Not Establish open item
Diagnose the admin's sequencing against Larson's migration playbook, and rewrite B6Decide the admin — by manufacturing the evidence as an experiment. (The playbook is Derisk → Enable → Finish, and it warns that starting with easy cases "creates a misleading sense of progress." Issue #5391the new admin's porting checklist — open since September 2023 states the inverse strategy verbatim ("tackle the easy pages first"), and the predicted failure is the observed one: half-ported settings, unticked checklist, hard core never started. B6Decide the admin — by manufacturing the evidence becomes "port one hard screen by hand" — which manufactures the evidence the funding decision has lacked for three years. Attribution check: the three-phase playbook is Larson's, verified against the primary source; the "agents excel at this work class" claim is not his — it is this framework's own estimation discipline, and is cited as such)
The $45,760 admin purchase shows “the project's missing completion gate appearing in a purchase order rather than in code” — no definition of finished existed.
A definition existed. Issue #5391the new admin's porting checklist — open since September 2023 (open since Sept 2023) publishes the porting checklist with an explicit sequencing rationale, and a Q2 2023 blog post narrated the plan. But not one of its six boxes has been ticked in three years — including Settings > Zones, which the code shows as fully ported. Corrected to: the gates were built and nobody is accountable for closing them. Also found: milestones exist, and the 5.0 milestone holds zero issues
R1, ranked first: “no automated dependency updating and no vulnerability audit step — a vulnerable dependency reaches every store, and you would learn from a downstream report.”
Wrong, and it was the top-ranked risk. The published security policy shows a HackerOne disclosure program, automated security dependency updates, an 18-month patch window over three versions, two mandatory reviews before merge, MFA on release accounts, and a three-phase coordinated disclosure — with five advisories published 2020–2022. R1Routine dependency drift between security releases downgraded to routine version drift and dropped out of the top three; the register now cuts to R3The half-built admin becomes a permanent third state, R2Two firms are 78% of the money and most of the code, R4. Assessing security from repository files alone missed a process documented one redirect away
Component table “Ruby files” figures: 855 / 328 / 278 / 193 / 166 / 98.
Every one double-counted. The count included *_spec.rb, so the Ruby and Test columns overlapped entirely — old figure = new Ruby + Specs in every row. Recounted excluding specs: 543 / 235 / 165 / 101 / 79 / 57. Adding an ERB column surfaced what the Ruby count was hiding: the old admin is 79 Ruby files and 277 view templates, giving a second, independent measure of the admin port at ~40% by template count
“The governance document defines no mechanism whatsoever for deciding technical direction, so no forum has the standing to decide the admin's fate.”
Overstated. The document assigns the Core Team "final decision as to what goes into the core," and stakeholders do hold documented weekly meetings — though those are explicitly scoped to "non-technical ways… conferences… marketing… funds." Corrected to: authority is assigned and meetings exist; what is absent is a venue, cadence and published record for technical decisions. Reframes the fix from creating governance to publishing it, and adds bet B10Publish technical decisions — restart the status posts
The new storefront has zero tests.
Wrong, and it inverted the finding. It holds 64 spec files and 5,510 lines, in templates/spec/ — because a Rails application template copies its specs into the generated app. The check looked for storefront/spec and found nothing. CI runs the suite end-to-end in a generated store on every push. The storefront moves from projected to confirmed credit, and "7 weeks old" becomes "years old, seven weeks in this repo"
Present spending as one table combining year-by-year totals with all-time recipient totals.
Misleading — reading across a row produced false statements ("2020 · Logicielle B.V." implied a payment that happened in 2024). Split into two tables. The corrected per-year view exposed the finding the broken one hid: each active year funded essentially one engagement, and July 2025 is the third such engagement to end, not a project giving up. Also corrected: Logicielle sent 16 invoices, not 22
Re-verify the $132,180 balance under challenge. (Survived, and strengthened. Two independent endpoints agree exactly; querying all expense states (not just paid) confirms nothing is pending or approved. Two reconciliation gaps are now stated openly rather than glossed)
“$132,180 sitting idle” as a characterization of the project's investment.
Softened. That figure covers the Open Collective account only. Donated engineering time from the two agencies dwarfs it. The finding narrows to: the collectively-governed money has been static for 12.5 months while stated priorities went unfunded
Recommend adding CI that verifies the installation path.
Wrong — it already exists and is stronger. The installer workflow boots the generated app, asserts the homepage renders, and runs its test suite; a second workflow covers the extension generator. Third time in this audit a "missing capability" finding died on contact. The prior on this project has been calibrated too low, consistently
Locate the real gap: CI is green on an undocumented install path. (The composite action writes manifest.js before running the installer, working around an unmerged upstream Sprockets bug. Documented path ≠ tested path, which explains a decade of install issues. Became bet B9Dual asset-pipeline support, with an agent-executed migration)
Count 12 ERB asset files as Propshaft blockers.
Ten of the twelve are view templates responding to AJAX requests, which Propshaft never touches. Only two are asset ERBs, and one uses ERB for a single route helper
Add the Rails-generation gap as a distinct finding. (Rails 8 defaults to Propshaft; solidus_core hard-requires Sprockets. The differentiator is not "we use Rails" but "we use Rails as it is done now" — and on the foundation every store loads, Solidus is a generation behind)
Record the courtesy-window answers; stakeholders "none reached" → "partial". (The draft posted to the project's Slack drew a Core Team reply within the hour: §22's questions 1 and 5 answered, R3The half-built admin becomes a permanent third state lowered per its own pre-registered rule, the easy-first finding qualified — viability disputed, sequencing partly conceded. The general caveat "not 100% accurate" strikes nothing by itself: no specific claim was named, and the next specific dispute widens the search on that claim. One answer set is corroboration, not access — the unanswered follow-ups stay in §22)
Record the follow-up answers. (Same thread, second Core Team reply, ~an hour later: the admin is a priority, and the funding model is deliberate — independent devs funded from the collective so maintainers avoid the perception of profiting from it; funds-to-agencies work is fine when transparent and fairly priced; Solidus–Spree relations are "no beef these days, just different directions." Consequences compiled into R3The half-built admin becomes a permanent third state, the related-party callout — the missing arm's-length standard exists as a stated norm, written nowhere an approver would read — and §22 item 3, where the external-payee pattern is now explained while the identities stay open)
“The last blog post — October 2025. Nine months of public silence follow.”
A post exists that the original sweep missed: "Solidus Status Update – Solidus v4.7," published 5 May 2026, announcing the v4.7.0 release. Found during the rev-26 re-verification, confirmed by fetching the post itself. What survives is narrower: the monthly cadence did stop after October 2025, and the blog now speaks only on releases — one post in the last ten months. The correction moves in the subject's favour, like every prior correction in this log
Record the rev-26 re-verification (evidence window 8 Aug 2026). (R3The half-built admin becomes a permanent third state's pre-registered observable has not fired: five days after "a new candidate is in the works" was stated, the ledger's last debit is still July 2025, and the balance has grown to $133,750. The recurring-sponsor set is unchanged at nine, $1,931/month. The meta-gem, the unticked checklist, and the absent agent harness were each re-confirmed. The one genuinely new fact favours the project: forkata delivered the promised adoption of the stalled confirmation-dialog work as a fresh PR without the disputed dependency, #6528, on 30 July. Spree shipped v5.6.1 on 28 July)
“Tested against Rails 8.1 and Ruby 4.0 before either is released” — the test matrix covers versions that don’t exist yet.
Wrong on the dates, and the reader who owns this report caught it against the workflow file itself. Rails 8.1 was released 22 October 2025 and Ruby 4.0 in December 2025; Solidus added them to CI on 23 and 29 January 2026 — one to three months after release, not before. The matrix rows themselves were always real; the "unreleased" framing was a plausibility slip in the original sweep (version numbers that sounded like the future, never date-checked) and it survived twenty-six revisions. Corrected everywhere to what the evidence supports: the newest Rails and Ruby, adopted within weeks of release — still top-decile currency, one notch less extraordinary. Also notable: this is the first correction in the log that moves against the subject-looks-better direction the previous forty entries established
Restructure to framework v0.7 (this revision). (The Executive Summary is replaced by Policies & Operations — five standing rules, PL1–PL5, all in the proposed state because an outside auditor cannot accept policy for a project it does not own. The Easy Wins lane is added, and two former bets drain into it: B3 became E2 and E3, B4's in-repo half became E4; the ids stay retired. A Watchlist section now carries every review date. B9 gains a Refinement field; B6 was already the admin's refinement slice and is now named as such. No finding changed as a result of the restructure — the corrections in this revision all came from the re-verification, logged separately in entries 38 and 39 above)
Watchlist
Every date this report is waiting on, in one place — because a review date nobody is scheduled to see is no review date.
| Item | What fires it | When | Watched by |
|---|---|---|---|
| The next outgoing Open Collective expense — the observable that confirms the funded candidate R3The half-built admin becomes a permanent third state now rests on | Any debit in the public ledger | overdue — "in the works" was stated 3 Aug 2026; nothing has appeared | this report, at each revision |
| #6528Admin confirm modal without external dependency merging — the rescue mechanism completing its first full cycle | Merge or close | next release cycle | this report, at each revision |
| C8solidus_promotions — projected credit, overdue — the promotions credit, projected and overdue | A named removal release (B5Name the release that removes legacy promotions, PL1Every replacement names the release that removes what it replaces) | write off if still unscheduled at the next major release | proposed: Core Team |
| C9solidus_admin — projected credit, past the point of write-off — the admin credit, past the write-off point | A disposition under PL4Every parallel initiative gets a quarterly disposition, or the B6Decide the admin — by manufacturing the evidence experiment | first quarterly pass | proposed: Core Team |
| B9Dual asset-pipeline support review | Review date | 2027-01-25, or the first major release after merge | proposed: Core Team |
| The policy register — accepted, amended or rejected | Any PL row changing state; two quarters of silence is the pre-mortem's warning sign | 2027-02-08 | this report, at each revision |
| Whether Spree's commit volume is human or generated (§22What I Could Not Establish item 7) | Any public analysis of Spree's contribution mix | open | this report, at each revision |
What I Could Not Establish
Everything here is unverified. It should not be acted on as fact — and most of it would be resolved by a single conversation.
- Why the 2025 engagement was not renewed. The most valuable unknown in the report. The project has funded a developer three separate times (2020, 2024, 2025) and stopped three separate times, with completely dry years in between. So the question is not "why did funding stop" — stopping is normal here — but why this gap has run thirteen months when previous ones were eventually filled. Budget caution, a contractor moving on, a deliberate pause, or simply nobody proposing the next engagement all produce an identical ledger and imply opposite responses. Answered at rev 24: "No candidate. We have a new candidate in the works right now, but don't have anything to share other than that we are working on it" stakeholder. A staffing gap, not a decision to stop — and "in the works" is forward-looking: the next outgoing ledger expense is the observable that confirms it. As of 8 August it has not appeared.
- Why Nebulab wound down. The pattern is unambiguous; the cause is not. A business decision, a deliberate handover, or attrition all produce this curve.
- Who "Logicielle B.V." and "e.c441" are. Together they received $49,394 — nearly a third of all money ever disbursed — across 2024 and 2025. Identity is not resolvable from public records, and it determines whether that spending bought continuity or one-off work. Context at rev 25: external payees are the stated preference, not an anomaly — the collective deliberately funds independent devs with Solidus experience so maintainers stay clear of the money stakeholder. The identities stay open; the pattern no longer does.
- Whether the balance is reserved against something. No policy documents it, but a reason may exist in meeting minutes.
- Whether the Core Team considers the new admin alive. Inferred entirely from commit decay. A maintainer might say it is intentionally paced. This single answer moves R3The half-built admin becomes a permanent third state from high to low. Answered at rev 24: alive and deliberately paced — real stores use the incomplete admin in production today, a usage signal invisible to this audit's commit-decay reading stakeholder. R3 moves down as pre-registered; the reservation lives on the risk row itself.
- Branch-protection settings and core-team membership. Both need organization admin scope and returned permission errors rather than absences, so the security policy's "two mandatory Core Team reviews" rests on the published statement rather than on observed enforcement. The same limit applies to whether vulnerability scanning is switched on through GitHub's interface.
- Whether Spree's commit volume reflects human or generated work. One unverified third-party claim says the latter. It is the most consequential open question about the §09Spree, Measured comparison.
Where to ask — these channels are public and live
- Slack —
http://slack.solidus.ioredirects to a working shared invite. This is where the weekly stakeholder meetings, the support channel and the private partner channel live. - Security list —
groups.google.com/forum/#!forum/solidus-security - GitHub Discussions — including a "New Admin UI Ux" category this audit could not read through the API.
No public account of this decline exists
Targeted searches for reporting on Solidus stalling, being abandoned, or losing ground to Spree returned nothing — re-run on 8 August 2026 with the same result web. What exists instead is a layer of agency comparison articles, several dated 2026, still describing Solidus as showing "more consistent development" than Spree — the opposite of what the repositories show.
The public narrative has not caught up with the data, and the people best placed to write it are the two firms whose business depends on the platform.
The structural limit of this entire report
Until rev 24, no one from the project had spoken. Business objectives, priorities, and the judgment of which risks are worth acting on were all reconstructed from public records rather than stated by anyone — and the ranking still prunes against an inferred objective (that Solidus exists to enable its funding agencies' client work), an inference that is load-bearing for the entire prioritization. If it is wrong, the ranking changes — and so does the policy register, which is compiled from that same diagnosis.
The courtesy window narrowed the limit without removing it. One Core Team member — Jared Norman, Super Good — answered in the project's Slack, and his verdict on the report doubles as its epistemic status: "Being based on publicly available information, it's not 100% accurate and I don't necessarily agree with all of the assessments here, but it is definitely helpful to see how the public state of the project looks when taken in aggregate" stakeholder. No specific claim was disputed, so nothing is struck; the next specific dispute widens the search on that claim, per the contract. This revision's own blog-silence correction is a reminder the verdict was earned: the claim he could have named, a re-check found first.
The clearest illustration is decision-log entry 07: I read "open for a year" as "waiting for review" and built a diagnosis on it. One maintainer would have answered that in a sentence. Every revision of this report before rev 24 was inference standing in for a conversation nobody had had. Rev 24 was the first exception — and its first three answers each moved something.
Nothing here asks to be believed: every factual claim in this report carries a tag saying how it was arrived at, and the tags are counted by the build, never authored.
ALSO AS — presentation deck · markdown · json-ld