Evidence ledger
One row per claim in Where Shopify refused to rewrite, and where it rewrote three times: who published it, what grade it carries, when it was written, when the link was last checked, and the quote or figure it rests on. Nothing in the guide is cited from memory, so anything not in this table is not in the guide.
Field guide: Where Shopify refused to rewrite, and where it rewrote three times: a decade read from its repositories. Research date 2026-09-11. Every row was fetched in this session.
Corpus limit, stated up front. This session's network policy reached github.com and
raw.githubusercontent.com and nothing else. shopify.engineering, railsatscale.com,
bugs.ruby-lang.org, arxiv.org, usenix.org, web.archive.org, en.wikipedia.org and every
other host tested returned an egress block, including the hosts that carry Shopify's own
engineering writing and Ruby's issue tracker. Shopify's blog posts, conference talks, the MPLR
2023 YJIT paper and every incident report the company has published are therefore absent from
this ledger. What remains is the repository record: READMEs, changelogs, decision records,
issues and pull requests. That record is a partial and biased witness. It over-reports the parts
of the platform Shopify chose to open source, and it says almost nothing about the systems it
never published, among them the shard router, the pod topology and the Storefront Renderer.
Where a claim in the guide rests on reconstruction rather than a fetched quote, the guide says
so in the sentence.
Tiers follow the skill's hierarchy: postmortem, source, adr, casestudy, blog, paper,
talk, vendor.
| # | Org | Title | Tier | Published | Checked | URL | Claim taken from it | Supporting quote or figure |
|---|---|---|---|---|---|---|---|---|
| 1 | Shopify | semian | source | 2014 | 2026-09-11 | https://github.com/Shopify/semian | Shopify's answer to a slow dependency is an in-process bulkhead and circuit breaker, running since 2014 | "Semian is a library for controlling access to slow or unresponsive external services to avoid cascading failures."; "Semian is an extraction from Shopify where it's been running successfully in production since October, 2014."; adapters listed: MySQL2, Redis, Net::HTTP, ActiveRecord Trilogy, ActiveRecord PostgreSQL; 1.5k stars |
| 2 | Shopify | semian issue #244, "Feature Request: Throttle half_open -> closed attempts" | postmortem | 2019-07-02 | 2026-09-11 | https://github.com/Shopify/semian/issues/244 | Circuit-breaker recovery consumes a measured share of the capacity it is trying to restore, and the issue is still open seven years later | "every available worker (subject to the bulkhead configuration) will attempt the half_open -> closed transition"; with default MySQL settings (1.0s half-open timeout, 5.0s error timeout) approximately "16.7% of capacity goes toward re-opening the circuit", or 8.3% with bulkheads enabled; status: Open |
| 3 | Shopify | semian PR #247, "Throttle bulkhead from the circuit breaker on state transition" | source | 2019-07-04 | 2026-09-11 | https://github.com/Shopify/semian/pull/247 | The proposed fix couples two mechanisms that were deliberately independent, and has neither merged nor closed since 2019 | Author michaelkipper: "When the circuit is in an open state, we still allow all the workers that can acquire tickets to attempt the transition to half_open."; reviewer thegedge: "In the worst case scenario, where all workers had their circuit open at the same time, n - 1 workers will wait at least an additional error_timeout seconds after recovery."; status: Open |
| 4 | Shopify | semian PR #420, "WIP: Adapter for GitHub's Trilogy MySQL client" | source | 2022-10-03 | 2026-09-11 | https://github.com/Shopify/semian/pull/420 | Replacing the database driver under a monolith means re-deriving the failure taxonomy the resiliency layer depends on; this attempt was closed unmerged after six months | Opened 2022-10-03 by casperisfine, closed 2023-04-24 without merging; Trilogy "seems eager about closing unused connections"; the half-open resource timeout "proved incompatible with Trilogy's architecture, which necessitated creating entirely new client instances for reconnection" |
| 5 | Shopify | toxiproxy | source | 2014 | 2026-09-11 | https://github.com/Shopify/toxiproxy | Shopify built failure injection into every developer's environment rather than into a staging tier | "A TCP proxy to simulate network and system conditions for chaos and resiliency testing"; "We've been successfully using it in all development and test environments at Shopify since October, 2014."; "The existing ones we found didn't provide the kind of dynamic API we needed for integration and unit testing."; 12.3k stars |
| 6 | Rails (donated by Shopify) | bootsnap | casestudy | n/a | 2026-09-11 | https://github.com/rails/bootsnap | Shopify's boot-time work produced its largest published figure, and the gem now lives in the Rails organisation rather than Shopify's | "The core Shopify platform boots about 75% faster, dropping from around 25s to 6.5s"; "Discourse reports a boot time reduction of approximately 50%, from roughly 6 to 3 seconds"; repository is rails/bootsnap; 2.7k stars |
| 7 | operator report | bootsnap issue #144, "Rails boot failure when cache dir isn't writable" | postmortem | 2018-03-22 | 2026-09-11 | https://github.com/rails/bootsnap/issues/144 | A boot-time optimisation that assumes a writable disk turns a read-only container into a failed boot rather than a slow one | "Permission denied @ rb_sysopen - tmp/readonly/bootsnap-load-path-cache.29785.39297.tmp (Errno::EACCES)"; reported against "read-only docker images", particularly for worker processes; reporter asks that "Bootsnap logs a warning in this situation rather than failing to boot"; status: Closed |
| 8 | Shopify | packwerk | source | n/a | 2026-09-11 | https://github.com/Shopify/packwerk | Shopify's modularisation tool enforces boundaries statically inside one codebase instead of extracting services | README: packages, "package-level constant visibility", "help existing codebases become more modular without impeding development workflow"; epigraph: "I know who you are and because of that I know what you do. This knowledge is a dependency that raises the cost of change."; 1.9k stars |
| 9 | Shopify | packwerk USAGE.md | adr | n/a | 2026-09-11 | https://raw.githubusercontent.com/Shopify/packwerk/main/USAGE.md | Existing violations are recorded rather than blocking, which is what makes retrofitting boundaries onto a live monolith possible | package_todo.yml records existing violations and should be "worked off over time" rather than added to; enforce_dependencies: strict prevents new violations from being recorded |
| 10 | Shopify | packwerk PR #169, "Add caching to speed up bin/packwerk check" |
source | 2021-12-21 | 2026-09-11 | https://github.com/Shopify/packwerk/pull/169 | Static boundary enforcement at monolith scale is a build-time cost that has to be engineered, and an outside contributor engineered it | Opened 2021-12-21 by alexevanczuk, merged 2022-02-16; runtime on Shopify's monolith "reduced from 3 minutes 30 seconds to under 20 seconds"; "The caching is 100% based off of file contents"; cache size approximately 200MB, "comparable to bootsnap's 99MB and Sorbet's 148M" |
| 11 | Shopify | packwerk PR #389, closed unmerged | source | 2024-02-22 | 2026-09-11 | https://github.com/Shopify/packwerk/pull/389 | Shopify declined to link its own retrospective on Packwerk from the tool's README, on the grounds that the article would drift from the tool | Opened 2024-02-22 by caffeinefriend, closed unmerged 2024-05-02; rafaelfranca: "I don't think we need to link to external article in the README. Those articles get old and change and might no reflect what the tooling is anymore."; the article in question is "A Packwerk Retrospective" by Gannon McGibbon and Chris Salzberg |
| 12 | Shopify | packwerk closed-unmerged pull requests | source | n/a | 2026-09-11 | https://github.com/Shopify/packwerk/pulls?q=is%3Apr+is%3Aclosed+is%3Aunmerged | The tool is still maintained in 2026, and the rejection record is substantial | 65 closed-unmerged pull requests; most recent shown #462 "perf: Replace better_html dependency with herb", 2026-05-14 |
| 13 | Shopify | job-iteration | source | 2017-05 | 2026-09-11 | https://github.com/Shopify/job-iteration | The monolith is partitioned by tenant, and the job framework exists so tenants can be moved between shards without losing work | "Makes your background jobs interruptible and resumable by design."; "At Shopify, we also use it to interrupt workloads safely when moving tenants between shards and move shards between regions"; "In production since May 2017"; 1.3k stars |
| 14 | Shopify | identity_cache | source | n/a | 2026-09-11 | https://raw.githubusercontent.com/Shopify/identity_cache/main/README.md | Shopify's caching layer states its own inconsistency budget in the README rather than claiming correctness | "IdentityCache is never going to be 100% consistent, since cache invalidations can be lost."; loss sources listed include a "Database write performed that doesn't trigger an after_commit callback", a process "getting killed or crashing between the database commit and cache invalidation", "Network unavailability", and "Memcached unavailability" |
| 15 | Shopify | identity_cache issue #535, "Cache invalidations can be missed on rollout of schema changes" | postmortem | 2023-04-05 | 2026-09-11 | https://github.com/Shopify/identity_cache/issues/535 | Putting the schema version in the cache key turns any canary deploy into a window where invalidations are dropped | dylanahsmith: "Rollout of cache namespace changes can result in cache fills to the new namespace that aren't invalidated by cache invalidations from a process still using the old namespace"; the trigger can be as ordinary as changing Rails' ignored_columns; proposed fix moves the schema hash out of the key and adds a data_version UUID; status: Open |
| 16 | Ruby / Shopify | doc/jit/yjit.md | adr | n/a | 2026-09-11 | https://raw.githubusercontent.com/ruby/ruby/master/doc/jit/yjit.md | Shopify's JIT is a lazy basic-block-versioning compiler written in Rust and living inside CRuby, not a separate runtime | "YJIT is a lightweight, minimalistic Ruby JIT built inside CRuby"; "lazily compiles code using a Basic Block Versioning (BBV) architecture"; written in Rust, "rustc >= 1.58.0"; production success stories requested at ruby@shopify.com; cites the MPLR 2023 paper by Chevalier-Boisvert and others |
| 17 | Ruby | NEWS.md, Ruby 3.2 | source | Ruby 3.2 | 2026-09-11 | https://raw.githubusercontent.com/ruby/ruby/ruby_3_2/NEWS.md | The JIT crossed from experiment to supported feature in one release, on the strength of a year of production exposure | "YJIT is no longer experimental"; "Has been tested on production workloads for over a year and proven to be quite stable."; "Building YJIT now requires Rust 1.58.0+."; default --yjit-exec-mem-size changed to 64 (MiB); default --yjit-call-threshold changed to 30 |
| 18 | Ruby | NEWS.md, Ruby 4.0 | source | Ruby 4.0 | 2026-09-11 | https://raw.githubusercontent.com/ruby/ruby/ruby_4_0/NEWS.md | The successor JIT is shipping experimental and slower than the one it replaces, three years after the first one stabilised | "Introduce an experimental method-based JIT compiler"; "As of Ruby 4.0.0, ZJIT is faster than the interpreter, but not yet as fast as YJIT"; "When building Ruby, Rust 1.85.0 or later is required to include ZJIT support"; stated goal to "make ZJIT faster than YJIT and production-ready in Ruby 4.1" |
| 19 | Ruby / Shopify | doc/jit/zjit.md | adr | n/a | 2026-09-11 | https://raw.githubusercontent.com/ruby/ruby/master/doc/jit/zjit.md | The second compiler changes the fundamental bet: profile-guided and method-based rather than lazily specialising | "A method-based just-in-time (JIT) compiler for Ruby"; "uses profile information from the interpreter to guide optimization"; described as "an advanced prototype"; supports macOS, Linux and BSD on x86-64 and arm64/aarch64 |
| 20 | Shopify | yjit | source | n/a | 2026-09-11 | https://github.com/Shopify/yjit | The JIT started in a Shopify repository and ended up in the language, which is the whole strategy in one artefact | "Optimizing JIT compiler built inside CRuby"; "YJIT has been merged upstream, and is now an official part of Ruby 3.1+."; bug reports directed to the Shopify/ruby repository; 729 stars |
| 21 | Shopify | ruby (fork of ruby/ruby) | source | n/a | 2026-09-11 | https://github.com/Shopify/ruby | Shopify carries its own checkout of the language it runs on, and uses it as the intake for JIT bug reports | Description: "The Ruby Programming Language [mirror]"; fork of ruby/ruby; 101,766 commits on master; 105 open issues; 52 stars |
| 22 | Shopify | yjit-metrics | source | n/a | 2026-09-11 | https://github.com/Shopify/yjit-metrics | The runtime investment is continuously benchmarked in public, which is how a company keeps an upstream bet honest | "Tasks for benchmarking, building and collecting stats for YJIT"; "You can see the latest YJIT statistics, gathered with yjit-metrics, at speed.ruby-lang.org."; 1,682 commits |
| 23 | GitHub | trilogy | source | 2022, per row 24 | 2026-09-11 | https://github.com/trilogy-libraries/trilogy | Shopify's replacement MySQL client was somebody else's, already carrying a second production user | "Trilogy is a client library for MySQL-compatible database servers, designed for performance, flexibility, and ease of embedding. It's currently in production use on github.com."; "no dependencies outside of POSIX, the C standard library & OpenSSL"; 784 stars |
| 24 | Rails / Shopify | rails PR #47880, "Introduce adapter for Trilogy, a MySQL-compatible DB client" | adr | 2023-04-06 | 2026-09-11 | https://github.com/rails/rails/pull/47880 | Shopify ran the new driver in its monolith first, then upstreamed the adapter rather than maintaining a fork | Opened 2023-04-06 by adrianna-chang-shopify, merged 2023-04-17; Trilogy and its adapter were "open sourced by GitHub last year"; Shopify "adopted Trilogy successfully in our Rails monolith several weeks ago"; "copy everything verbatim for now to ensure full test coverage, and clean things up in a subsequent PR" |
| 25 | Shopify | krane | source | n/a | 2026-09-11 | https://github.com/Shopify/krane | Where Shopify adopted somebody else's platform it built a thin verdict layer on top rather than a platform of its own | "A command-line tool that helps you ship changes to a Kubernetes namespace and understand the result"; on kubectl: "it leaves its users with some burning questions: What just happened? Did it work?"; "At Shopify, we use it within our much-beloved, open-source Shipit deployment app."; 1.4k stars |
| 26 | Shopify | krane CHANGELOG | source | n/a | 2026-09-11 | https://raw.githubusercontent.com/Shopify/krane/main/CHANGELOG.md | The Kubernetes deploy tool was renamed rather than replaced, and is still tracking current Kubernetes releases in 2026 | "This is the final release of KubernetesDeploy. Version 1.0.0 will be released under the name Krane."; most recent entry, version 3.9.1: "Test against k8s 1.34" |
| 27 | Shopify | shipit-engine | source | n/a | 2026-09-11 | https://github.com/Shopify/shipit-engine | The deploy orchestrator is deliberately language-agnostic and script-shaped, which is what let one tool survive several platform changes | "a deployment tool that makes shipping code better for everyone"; "At Shopify, we've used Shipit to synchronize and deploy hundreds of projects across dozens of teams, using Python, Rails, RubyGems, Java, and Go."; works with "just about anything that you can deploy using a script"; 1.5k stars |
| 28 | Bytecode Alliance (originated at Shopify) | javy | source | n/a | 2026-09-11 | https://github.com/bytecodealliance/javy | Merchant code runs as WebAssembly, and the size of the module is the design constraint that decides which languages are allowed | "A Jav_aScript to Webassembl_y toolchain"; "create very small Wasm modules in the 1 to 16 KB range with use of dynamic linking"; "The default static linking produces modules that are at least 869 KB in size."; now "A Bytecode Alliance project"; 2.7k stars |
| 29 | Shopify | ruvy, archived | source | archived 2026-01-27 | 2026-09-11 | https://github.com/Shopify/ruvy | Shopify could not fit its own language into the sandbox it gives merchants, and archived the attempt in 2026 | "Ruvy aims to initialize the ruby VM using wizer and execute ruby code passed into the wasm."; "Ruvy is not currently compatible with Shopify Functions. This is due to the size of the Wasm modules produced by Ruvy exceeding the maximum size of Wasm modules supported by Shopify Functions."; archived by Shopify on 2026-01-27, read-only; 317 stars |
| 30 | Shopify | hydrogen | source | n/a | 2026-09-11 | https://github.com/Shopify/hydrogen | The current storefront stack is defined by its relationship to a third-party router, and the previous generation has been moved out of the repository | "Hydrogen lets you build faster headless storefronts in less time, on Shopify."; "Hydrogen is designed to dovetail with React Router, the modern multi-strategy router for React"; "Hydrogen legacy v1 has been moved to a separate repo"; 2.1k stars |
| 31 | Shopify | hydrogen-v1 | source | n/a | 2026-09-11 | https://github.com/Shopify/hydrogen-v1 | The superseded storefront framework kept shipping releases years after its successor, which is what deprecation actually costs | Banner: "⚠️ This is a legacy version of Hydrogen. See the latest available at https://github.com/Shopify/hydrogen ⚠️"; description "React-based framework for building dynamic, Shopify-powered custom storefronts."; 3.7k stars |
| 32 | Shopify | hydrogen-v1 commit history | source | 2025 | 2026-09-11 | https://github.com/Shopify/hydrogen-v1/commits/main | Releases on the legacy branch continued into 2025 | Most recent commit "[ci] release v1.x-2022-07 (#2569)", 2025-03-19; release branch named v1.x-2022-07 |
| 33 | Remix / Shopify | react-router decision 0005, "Remixing React Router" | adr | 2022-07-29 | 2026-09-11 | https://github.com/remix-run/react-router/blob/main/decisions/0005-remixing-react-router.md | The framework Shopify bought moved its own data APIs down into the router, a re-platforming decided in the open | Status: Accepted, dated 2022-07-29; "In Remixing React Router, Ryan gives an overview of the work we started out to do in bringing the data APIs from Remix (loaders, actions, fetchers) over to react-router"; router logic moved to @remix-run/router "with zero dependencies"; useTransition renamed to useNavigation |
| 34 | Remix / Shopify | react-router decision 0011, "routes.ts" | adr | 2024-09-18 | 2026-09-11 | https://github.com/remix-run/react-router/blob/main/decisions/0011-routes-ts.md | Each convention change ships with an adapter, which is an admission that the migration cost is real | Status: Accepted, dated 2024-09-18; "when Remix changed its routing conventions between v1 and v2, some users experienced friction"; the @react-router/remix-routes-option-adapter package "provides a remixRoutesOptionAdapter function" for migrating Remix route config into React Router v7 |
| 35 | community | remix discussion #10333 | source | 2024-12-14 | 2026-09-11 | https://github.com/remix-run/remix/discussions/10333 | Users of the framework Shopify owns report the migration tax in their own words | Title: "Please reconsider the decision to (temporarily?) abandon the Remix name and instead release Remix v3 as a thin wrapper around React Router 7", opened 2024-12-14 by torbensky; "So you're asking Remix adopters to migrate Remix -> React Router -> Remix at some future date?"; another commenter: "started three remix projects over the past 12 months and the setup was totally different every time" |
| 36 | Remix / Shopify | remix repository, Remix 3 | source | n/a | 2026-09-11 | https://github.com/remix-run/remix | The framework has moved again, this time away from React and toward a model-first design | "Welcome to Remix 3!"; "The fully-stacked web framework."; "the source repository for Remix 3. It is under active development."; stated principles include "Model-First Development (optimizing for LLMs)", "Building on Web APIs", "Minimizing dependencies"; 33.3k stars |
Tier mix
| Tier | Rows |
|---|---|
| postmortem | 4 |
| source | 24 |
| adr | 6 |
| casestudy | 1 |
| blog | 0 |
| paper | 0 |
| talk | 0 |
| vendor | 0 |
Blog, paper and talk rows are zero because the hosts that carry them were unreachable from this session, not because the material does not exist. Shopify has published extensively on all three of the arcs traced here. A reader with an unrestricted network should start with the Packwerk retrospective named in row 11 and with the MPLR 2023 YJIT paper cited in row 16, both of which this guide can name but could not read.
Distinct hosts
Two: github.com and raw.githubusercontent.com. The skill's breadth check wants eight. The
gap is a property of the session, and it is recorded in the guide itself rather than hidden.
A note on the Published column. Where a row reads n/a the repository page did not state a
creation date and the GitHub API was rate-limited in this session, so no year is asserted. Dates
that do appear were read directly off the artefact: an issue header, a pull-request timeline, an
archive banner, a commit row or a sentence in the README.