38 slides · use ← → · built from the report

existing-system audit

Solidus

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.

See the full report ↗1 / 38

A set of Rails commerce libraries. You run everything; you own everything.

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.

See full: What Solidus actually is ↗2 / 38

observed

Technically healthy, strategically adrift.

Solidus is technically healthy and strategically adrift. Both are true, and the gap between them is the whole story.

See full: Policies & Operations ↗3 / 38

observed

The whole story in four numbers.

  • 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
See full: Policies & Operations ↗4 / 38

PL1 · direction · proposed

Every replacement names the release that removes what it replaces

Addresses
RC1 (Migrations are engineered but never scheduled), D1 (Three unfinished rewrites)
Relation
amends S3 (Ship replacements alongside the old version as opt-in) by adding the exit criterion it lacks; reinforces S2 (Never 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

The project engineers migrations well and never schedules them — RC1 (Migrations are engineered but never scheduled) is the mechanism behind the largest recurring cost in the ledger, D1 (Three 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 B5 (Name the release that removes legacy promotions), which has been free to do for two years.

See full: The proposed policy register ↗5 / 38

PL2 · allocation · proposed

Collective money buys named outcomes, not time

Addresses
RC1 (An unfunded initiative sitting next to an unspent budget), R3 (The half-built admin becomes a permanent third state), F1 (The 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

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 (F1 (A 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 — 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.

See full: The proposed policy register ↗6 / 38

PL3 · guidance · proposed

Decisions are published where adopters can read them

Addresses
D2 (Governance describes a project that no longer exists), D3 (Architectural decisions are never recorded), R4 (Spree takes the new-project market)
Relation
ratifies S1 (Reject the JavaScript-framework direction on purpose) by moving the published strategy into the project's own artifacts; reinforces S5 (Merge authority belongs to a self-appointing Core Team)
Operations
both channels already exist and are dormant — restarting them costs an hour a month; E1 (Tick the already-done boxes on the porting checklist) and E5 (Republish 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

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 (S1 (Reject 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 ; this rule turns that from an occasional act into a habit.

See full: The proposed policy register ↗7 / 38

PL4 · approval · proposed

Every parallel initiative gets a quarterly disposition, recorded publicly

Addresses
R3 (The half-built admin becomes a permanent third state), D1 (Three unfinished rewrites), RC2 (The steward changed in the code but not in the governance)
Relation
amends S5 (Merge 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 PL3 (Decisions 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

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 (S5 (Merge authority belongs to a self-appointing Core Team), D2 (Governance 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 (R3 (The half-built admin becomes a permanent third state)) hide it for two more years.

See full: The proposed policy register ↗8 / 38

PL5 · guidance · proposed

A departing contributor's in-flight work is adopted or closed within a release cycle

Addresses
RC2 (The steward changed in the code but not in the governance), F2 (Built by one organization, handed to nobody), F3 (The 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

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 (F3 (The 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 — 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.

See full: The proposed policy register ↗9 / 38

inferred

Five standing rules, all proposed, none requiring a volunteer to work.

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.

See full: What the register deliberately does not cover ↗10 / 38

observed

Forked from Spree in 2015. Its creator left in 2018; its steward, in 2024.

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.

See full: Timeline ↗11 / 38

observed

Every serious year funded a single engagement. 2021 and 2026: nothing.

Spending by year — and who received the bulk of it
YearPaid outExpensesWhere it went
2019$11,76810Conference costs — Sean Denny 43%, Cindy Backman 42%
2020$35,73624Peter Berkenbosch 80% — monthly "Development & Maintenance"
2021$00nothing at all
2022$5001One conference video-editing invoice
2023$45,7607The admin — Nebulab 79%, Andrea Iurisci 21%. 100% of the year.
2024$32,50616Logicielle B.V. 100% — 16 development invoices, Aug–Dec
2025$16,8886"e.c441" 100% — 6 development invoices, Feb–Jul
2026$00nothing at all
See full: Where the money went — and when it stopped ↗12 / 38

observed

Funded development stopped July 2025. $133,750 sits unspent while income keeps arriving.

The money in one line: funded development stopped in July 2025, thirteen months of income have arrived since, and $133,750 sits unspent.

See full: Who can spend it ↗13 / 38

observed

Commit volume: the 2023 spike is one organization arriving and leaving.

20152,194
20162,244
20171,980
20181,070
2019883
20201,252
2021817
2022828
20231,810
20241,016
2025685
2026 ytd223
See full: Development volume by year ↗14 / 38

observed

Three rewrites look stalled. On the evidence, only the admin actually is.

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.

See full: The extension ecosystem ↗15 / 38

observed

The handover, in commits: 696 to 46 to 4 to zero.

Person (organization)20222023202420252026
Elia Schito (Nebulab)1336964640
Alberto Vena (Nebulab)7023252123
Rainer Dema (Nebulab)168200
Super Good Software (all)34314062136
See full: The withdrawal, year by year ↗16 / 38

observed

The steward wrote 60% of 2023's code — and 0.8% of last year's.

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.

See full: Where decisions get made — and where they don't ↗17 / 38

observed

An excellent machine: the newest Rails and Ruby, adopted within weeks of release.

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.

See full: The Machine ↗18 / 38

observed

$45,760 and three years bought version 0.4. 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.

See full: Why it stopped — three compounding causes ↗19 / 38

observed

Solidus and Spree, measured on the same day.

MetricSolidusSpree
Commits in the last 52 weeks (GitHub's own series — the git log in §06 counts 493 over the same window; the 5.5× ratio uses one instrument on both sides)4002,190 — 5.5×
GitHub stars5,31715,572
Forks1,4005,287
Latest releasev4.7.0 · 15 Apr 2026v5.6.1 · 28 Jul 2026
Platform releases in July 202606
Cumulative package downloads3.22M2.85M
See full: Spree, Measured ↗20 / 38

observed

Spree rides a business; Solidus rides a donation pot.

Spree's open source is a marketing cost carried on a real business; Solidus's is carried on a $25k-a-year donation pot.

See full: Feature comparison ↗21 / 38

observed

Spree came back shipping 5.5× the code, with enterprise revenue behind it.

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.

See full: Feature comparison ↗22 / 38

observed

The strategy in force: real rules, enforced by machines — written down almost nowhere.

RuleWritten where?Health
S1Reject the JavaScript-framework direction on purpose. Simplicity, one stack, no fees, distributed governance.on the lead maintainer's company blogThe project's actual strategy — stated, just not here
S2Never break an existing store. Deprecate before removing; back-port fixes to old versions.ratifiedHolding — at a cost nobody has priced
S3Ship 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 governanceWorking — see the promotions migration guide
S4Core stays lean; capabilities live in separate extensions.nowhereWeakening — four official extensions dormant
See full: The Strategy Already in Force ↗23 / 38

observed

The strategy in force: real rules, enforced by machines — written down almost nowhere.

RuleWritten where?Health
S5Merge authority belongs to a self-appointing Core Team. Money buys votes on spending, never on code.ratifiedYes — the separation is deliberate and healthy
S6Quality is enforced by machines; style is not argued about.only in CI configThe best-functioning rule in the project
S7All delivery is done by humans.by omissionUntested — no agent harness exists
See full: The Strategy Already in Force ↗24 / 38

inferred

Losing the steward is this project's normal condition.

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.

See full: Root Causes ↗25 / 38

observed

An unfunded initiative sitting next to an unspent budget.

The two causes compound into a single condition: an unfunded initiative sitting next to an unspent budget.

See full: Root Causes ↗26 / 38

inferred

Five risks, ranked by damage times likelihood times how quietly they land.

RiskFlagLikelihoodWould you notice?
R1Routine dependency drift between security releasesdowngradedLow for disclosed vulnerabilities — that path is covered. Medium for driftFor a disclosed CVE, yes. For gradual drift, no
R2Two firms are 78% of the money and most of the codehard to detectMedium — this has already happened twiceNot for months. A departure looks exactly like a quiet quarter
R3The half-built admin becomes a permanent third statehard to detectLowered at rev 24 — deliberately paced by the Core Team's account; the confirming observable has not fired yetNo. Every signal a maintainer looks at is green
R4Spree takes the new-project marketeasy to see coming
R5The new storefront breaks existing extensions by design
See full: Risk Register ↗27 / 38

inferred

The risk map: the stalled admin is both likely and quiet.

Impact if it lands
Plan & monitorAct nowWatchlistContingencyR3The new admin stays stalled — placed high because the silence is the findingR2Contributor concentration — one organization's withdrawal already proved the shapeR4Spree competition compounds while Solidus stands stillR5Extension breakage on major upgradesR1Routine dependency drift between security releases
Likelihood inside twelve months
  1. R3The new admin stays stalled — placed high because the silence is the finding
  2. R2Contributor concentration — one organization's withdrawal already proved the shape
  3. R4Spree competition compounds while Solidus stands still
  4. R5Extension breakage on major upgrades
  5. R1Routine dependency drift between security releases
Risk exposure.
See full: Risk Register ↗28 / 38

inferred

Four debts, paid every release — the biggest is invisible on every dashboard.

DebtKind
D1Three unfinished rewritesstrategic
D2Governance describes a project that no longer existsorganizational
D3Architectural decisions are never recordedknowledge
D4The agent harness, and two small automation gapstechnical
See full: Debt Ledger ↗29 / 38

observed

Nine credits booked: every machine investment paid back; both product bets stalled.

CreditStatus
C1Test matrix current to the newest Rails and Rubyconfirmed
C2Deprecation build gateconfirmed
C3Automated back-portingconfirmed
C4Automated code styleconfirmed
C5Release and changelog automationconfirmed
C6Reproducible development environmentconfirmed
C7The storefrontconfirmed
C8solidus_promotionsoverdue
C9solidus_adminpast the point of write-off
See full: Credit Ledger ↗30 / 38

inferred

A role, not a comeback: the framework you can still own in ten years.

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.

See full: Choose a Role ↗31 / 38

inferred

Three legitimate roles. Drifting between them is the only illegitimate option.

The three roles, side by side
RoleThe moveThe catch
A — Steward the installed baseNo new initiatives; guarantee upgrades and security; finish promotions; cancel the admin and storefrontAn explicit acceptance of managed decline — some contributors will leave
B — Contest the agent channelShip the missing agent harness; sell "one runtime, one test command" to agent-driven buildersSpree shipped theirs first — a modifier on Role A, not an alternative
C — Converge with SpreeFold back into the project Solidus forked fromNobody inside will propose it, which is exactly why it must be written down
See full: Choose a Role ↗32 / 38

inferred

Seven bets — most cost a meeting, a policy statement, or one hard screen.

BetVerdictAddressesCost
B2Restart funded development — buying an outcome, not sprintsDoR3, D1one meeting agenda item
B5Name the release that removes legacy promotions — a policy statement, not labour; the first invocation of PL1DoD1, RC1free
B6Decide the admin — by manufacturing the evidence, not deliberating without itDecideR3, D1one hard screen
B7Match Spree's React storefrontKillR4
B8GraphQL / headless surfaceWaitR4
See full: Bets — for you to set ↗33 / 38

inferred

Seven bets — most cost a meeting, a policy statement, or one hard screen.

BetVerdictAddressesCost
B9Dual asset-pipeline support, with an agent-executed migrationDoR1, D3, D4see template
B10Publish technical decisions — restart the status posts, file forward-looking roadmap items; the one-time act behind PL3DoD2, D3, S1, R4an hour a month
See full: Bets — for you to set ↗34 / 38

inferred

The sequence: decisions now, delegable work after.

Now — weeks
Next quarter
Horizon 2
Bets
B6 · port one hard admin screen
B10 · publish decisions again
E1–E5 · drain the fast lane
PL1–PL5 · accept, amend or reject the register
B5 · name the release that drops legacy promotions
Role A or A+B declared publicly
See full: Sequence ↗35 / 38

inferred

The fixes are cheap: publish decisions, name dates, fund outcomes — not sprints.

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.

See full: Sequence ↗36 / 38

Don't take the deck's word: every claim is tagged and checkable in the report.

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.

See full: What I Could Not Establish ↗37 / 38

Before the conclusions

118 tagged claims

observed58%68
web27%32
stakeholder10%12
inferred5%6
assumed0%0

How much of what you just heard was actually observed.

See the full report ↗38 / 38