Skip to content

Stoplight v6.0.0 🚀 - #932

Open
bolshakov wants to merge 240 commits into
mainfrom
release/v6.0.0
Open

Stoplight v6.0.0 🚀#932
bolshakov wants to merge 240 commits into
mainfrom
release/v6.0.0

Conversation

@bolshakov

@bolshakov bolshakov commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Stoplight 6.0 is built around a single idea: a light is a named thing your application declares once, not an object
you rebuild at every call site.
Almost everything else in this release follows from that — a real registry, an
authoritative inventory for the Admin dashboard, a telemetry bus, and a Redis layer that finally agrees with itself
about what time it is.

The most visible consequence is speed. The way most applications call Stoplight — Stoplight("name").run { ... }
is 5.6x faster with the in-memory data store and 2.2x faster with Redis, and a Redis sliding window now costs the
same at 10 requests per second as at 10,000.

This is a major release with breaking changes. They are listed at the end of these notes, and UPGRADING.md
walks through every one of them, roughly ordered from "needs some thought" to "find and replace". For most applications
the upgrade is smaller than the list suggests.


Faster by default

Most applications use Stoplight the same way, and have since the beginning:

Stoplight("Payment Service").run { payment_gateway.charge(order) }

We benchmarked that pattern in three configurations, on the previous release and on 6.0, with both data stores. Each
row is the same code called in a tight loop with benchmark-ips, reported as the median of five runs next to the
number of Ruby objects allocated per call. Every light is green and has no telemetry subscribers. Timings came from an
Apple M1 Max on Ruby 3.2.4 with a local Redis. Absolute numbers vary by machine; the ratios are the stable part.

Per call, in-memory data store

Call 5.8.3 6.0 Change
Stoplight("name").run { } 20.9 µs, 65 allocations 3.7 µs, 6 allocations 5.6x faster, 91% fewer allocations
Stoplight("name", window_size: 300).run { } 21.6 µs, 66 allocations 6.9 µs, 17 allocations 3.1x faster, 74% fewer allocations
Stoplight("name", window_size: 300, traffic_control: :error_rate).run { } 22.1 µs, 67 allocations 7.5 µs, 18 allocations 3.0x faster, 73% fewer allocations

Passing settings to Stoplight() costs a little more than passing none, because 6.0 checks them against the
registered configuration on every call. Registering at boot and calling Stoplight.light("name") at the call site
is the cheapest path of all: it is the same lookup as the first row, whatever the light's settings.

Per call, Redis data store

Call 5.8.3 6.0 Change
Stoplight("name").run { } 765 µs, 774 allocations 349 µs, 71 allocations 2.2x faster, 91% fewer allocations
Stoplight("name", window_size: 300).run { } 777 µs, 780 allocations 357 µs, 86 allocations 2.2x faster, 89% fewer allocations
Stoplight("name", window_size: 300, traffic_control: :error_rate).run { } 776 µs, 781 allocations 359 µs, 87 allocations 2.2x faster, 89% fewer allocations

Every #run makes the same number of Redis round trips while the circuit is closed as before: one to read the state
and one to record the result.

Memory

A sliding window in Redis no longer grows with traffic. This is a light with window_size: 300 after five seconds
of load, measured as the bytes Redis holds for it:

Requests in the window 5.8.3 6.0
500 60 KB 1.2 KB
5,000 667 KB 1.2 KB
18,500 2.4 MB 1.2 KB

5.8.3 keeps roughly 130 bytes per request until the window slides past it. 6.0 keeps one small entry per second, so
a window costs the same at 10 requests per second as at 10,000. The in-memory store already bucketed by the second,
and its window footprint is unchanged.

A registered light costs more at rest than it used to:

Per registered light 5.8.3 6.0
In-memory data store, heap per light 1.8 KB 3.4 KB
Redis data store, bytes per light 200 B 640 B
Redis data store, 10,000 lights 2.7 MB 7.2 MB

Traffic does not grow memory in either version. One default light run at 100 to 100,000 requests per second for
three seconds showed no growth in the process or in Redis.

The sections below explain where each of these numbers comes from.


Register once, look up by name

In 5.x, every Stoplight("Payment Service", threshold: 5) call built a brand-new light. Nothing tied the call sites
together, so two files could configure the same name differently and both would quietly work — which settings a
process ended up with depended on which file it happened to execute first.

6.0 makes registration explicit. Declare your lights at boot:

# config/initializers/stoplight.rb
Stoplight.register("Payment Service", threshold: 5, cool_off_time: 60)
Stoplight.register("Search", threshold: 10, window_size: 300)

Then look them up by name, with no settings list to keep in sync:

Stoplight.light("Payment Service").run { payment_gateway.charge(order) }

Stoplight.light takes a name and nothing else. If that name was never registered it raises
Stoplight::Error::UnregisteredLightError instead of silently creating a light with default settings — a typo in a
light name is now a loud failure rather than a circuit breaker that never trips the way you expected.

Stoplight() still works everywhere it used to. It registers on first call and returns the cached instance
afterwards. What it no longer does is let two call sites configure the same name differently — that now raises. The
error message names the file and line where the light was first registered, and its backtrace starts at the
conflicting call in your own code rather than inside Stoplight, so the disagreement is obvious. Dynamic names
(Stoplight("api-#{endpoint}")) still work: caching is per name, so each distinct name registers once.

This is where the per-call numbers above come from. Each Stoplight("name") call used to build a light from scratch:
merge the configuration, construct the storage wrappers, wire the notifiers, and with Redis, load the Lua script for
the new instance in an extra round trip. Everything was discarded when the block returned. Now the call is a lookup
in the registry, and when you pass settings, a digest of them compared against the registered ones.

The registry also writes each light's configuration to your data store, which is what finally gives the Admin
dashboard an authoritative list of every light your application defines — including ones that have never run. It
is also why a registered light costs more at rest than before: 6.0 keeps each light's configuration digest and
registration site in memory to detect conflicting call sites, and a registry entry in Redis for the dashboard.

@bolshakov (#681, #733, #734, #737, #739, #811, #826, #828, #928, #931)


Telemetry: subscribe to what your circuit breakers are doing

Stoplight has always had notifiers, but they only fired on state transitions and only told you the color changed.
6.0 adds a proper in-process event bus. Every light publishes what it does — runs, trips, recovery attempts, manual
locks, registration — and any part of your application can subscribe without touching the light's own code.

Stoplight.telemetry.subscribe(Stoplight::Telemetry::TrafficBreached) do |envelope|
  logger.warn("#{envelope.light_name} tripped: #{envelope.payload.failure&.exception&.message}")
end

Stoplight.telemetry.subscribe(Stoplight::Telemetry::RecoverySucceeded) do |envelope|
  logger.info("#{envelope.light_name} recovered")
end

Every event arrives in an Envelope carrying system_name, light_name, occurred_at, and the typed payload.
The payloads are Data objects, so they destructure cleanly and fail loudly on a typo:

Stoplight.telemetry.subscribe(Stoplight::Telemetry::RunCompleted) do |envelope|
  run = envelope.payload
  statsd.timing("stoplight.run", run.duration_ms, tags: [
    "light:#{envelope.light_name}",
    "outcome:#{run.outcome}",
    "color:#{run.color}",
    "fallback:#{run.fallback_used}"
  ])
end

The full event set: RunCompleted, TrafficBreached, RecoveryStarted, RecoveryProbeCompleted,
RecoverySucceeded, RecoveryFailed, LockChanged, and LightRegistered. Subscribe with no filter for the
firehose, with a specific class for one event, or with a module for a family of them.

Two properties matter for production use. Event payloads are built lazily — if nothing is subscribed to
RunCompleted, nothing is allocated for it, so the bus costs you nothing when you aren't using it. And a raising
subscriber cannot break your application
: exceptions from handlers are routed to your error_notifier, never back
into the protected block.

The notifiers option is now implemented as a telemetry subscriber itself, so anything a notifier can do, a
subscription can do with more event types and more detail. The stoplight-statsd gem is built exactly
this way. See the Telemetry guide for the complete reference.

This is what it looks like once the events reach Grafana — every light's run rate by outcome, with a circuit
blocking traffic while it is red, and run duration percentiles across the fleet:

Stoplight metrics in Grafana

@bolshakov (#721, #723, #724, #726, #741, #742, #854, #878, #881, #907, #909, #910, #911), @Zainulhassan01 (#852)


One dashboard, every system

Named systems — isolated registries with their own data store, notifiers, and configuration — are now a first-class
public API via Stoplight.register_system:

Payments  = Stoplight.register_system("Payments",  threshold: 3, cool_off_time: 30, data_store: payments_redis)
Analytics = Stoplight.register_system("Analytics", threshold: 5, cool_off_time: 60, data_store: analytics_redis)

Payments.register("stripe")
Analytics.register("amplitude")

Payments.light("stripe").run { charge_card }

The same circuit name in two systems is two completely independent circuits, which is what makes this work for
multi-tenancy and for separating failure domains with different SLOs.

The Admin dashboard now understands all of them. Register your systems with it and a switcher appears in the top
navigation:

Stoplight::Admin.configure do |config|
  config.add_system Payments
  config.add_system Analytics
end

mount Stoplight::Admin => "/stoplights"

Underneath, lights are addressed by stable IDs through system-scoped RESTful routes. Previously the dashboard used
light names as URL identifiers, which broke on names containing slashes or spaces and collided across systems.

There's also a read-only mode, which is what you want if you're exposing the dashboard more widely than your
on-call rotation:

Stoplight::Admin.configure do |config|
  config.add_system Payments
  config.read_only = true
end

Everything stays visible; lock, unlock, and remove are hidden and disabled, and any request that would change state
returns 403. For the pre-built Docker image, set STOPLIGHT_ADMIN_READ_ONLY=true.

@bolshakov (#712, #719, #803, #808, #809, #859, #861, #863, #864, #867, #868, #869, #912)


Redis tells the time now

Stoplight 5.0 shipped clock skew detection: a probabilistic check that warned you when your application servers and
Redis disagreed about the current time. It was a useful diagnostic, but it only told you that you had a problem.

6.0 removes the problem. Every time-dependent decision — state transitions, cool-off expiry, metrics bucketing,
recovery timing — is now made from Redis's own clock, read inside the same Lua script that performs the write.
Every instance reads the same time no matter what its host believes, so a drifting server can no longer trip a
circuit early, hold one red past its cool-off, or corrupt a sliding window.

It is also cheaper. Every write used to carry a timestamp computed in Ruby, and window writes carried a random request
id as well, both generated on every call. Now the script reads the time itself, so the client sends less and allocates
less per call. That, and the removal of the compatibility wrappers that sat between a light and its storage, is why a
run on Redis allocates fewer objects even after the cost of building the light is taken out of the picture.

Because the coordination problem is solved at the source, there's nothing left to warn about, and
warn_on_clock_skew: has been removed.

@bolshakov (#917, #918, #921, #925, #926)


Sliding-window metrics that scale with the window, not with traffic

5.8.3 stored one sorted-set member in Redis per request and counted them on every read, so a busy light carried a large
and growing set. 6.0 keeps per-second success and failure counters, running totals, and an index of bucket timestamps,
and evicts expired buckets in batches inside the same Lua script that records the result.

That is where the flat 1.2 KB column above comes from: memory is a function of your configured window size, not
of how much traffic flows through the circuit. Writes stay amortized O(1), and the old keys expire naturally after you
upgrade — there's no migration step.

@bolshakov (#904)


Features and improvements

Fixes


Breaking changes

This is the price of the above. Each item links to its section in UPGRADING.md, which has the
before/after code and the reasoning. Most of them are a find and replace; the first two need a look at how your
application configures its lights.


Thank you

This release had more new contributors than any before it. Thank you to @Lokideos, @johnsonsirv, @nebiyuelias1,
@ankuanku1, @shkrt, @OursCodeur, @henriquejsza, @snowyukitty, @arvindpz, @pollychen-lab, @Zainulhassan01, @mausamp,
@oiahoon, and @SAY-5.

Routine dependency updates, release bookkeeping, CI configuration, and internal tooling changes are intentionally
omitted from this list.

Full Changelog: v5.8.3...v6.0.0

bolshakov and others added 30 commits March 9, 2026 18:05
Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.289.0 to 1.292.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](ruby/setup-ruby@19a43a6...4eb9f11)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.292.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [rubygems/release-gem](https://github.com/rubygems/release-gem) from 1.1.2 to 1.1.3.
- [Release notes](https://github.com/rubygems/release-gem/releases)
- [Commits](rubygems/release-gem@1c162a7...2cceab0)

---
updated-dependencies:
- dependency-name: rubygems/release-gem
  dependency-version: 1.1.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.12.0 to 4.0.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](docker/setup-buildx-action@8d2750c...4d04d5d)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.292.0 to 1.293.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](ruby/setup-ruby@4eb9f11...dffb23f)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.293.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [rubygems/release-gem](https://github.com/rubygems/release-gem) from 1.1.3 to 1.1.4.
- [Release notes](https://github.com/rubygems/release-gem/releases)
- [Commits](rubygems/release-gem@2cceab0...e9a6361)

---
updated-dependencies:
- dependency-name: rubygems/release-gem
  dependency-version: 1.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the bundler group with 1 update in the / directory: [json](https://github.com/ruby/json).


Updates `json` from 2.18.1 to 2.19.2
- [Release notes](https://github.com/ruby/json/releases)
- [Changelog](https://github.com/ruby/json/blob/master/CHANGES.md)
- [Commits](ruby/json@v2.18.1...v2.19.2)

---
updated-dependencies:
- dependency-name: json
  dependency-version: 2.19.2
  dependency-type: indirect
  dependency-group: bundler
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.293.0 to 1.295.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](ruby/setup-ruby@dffb23f...319994f)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.295.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.15.1 to 2.16.0.
- [Release notes](https://github.com/step-security/harden-runner/releases)
- [Commits](step-security/harden-runner@58077d3...fa2e9d6)

---
updated-dependencies:
- dependency-name: step-security/harden-runner
  dependency-version: 2.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.295.0 to 1.296.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](ruby/setup-ruby@319994f...eab2afb)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.296.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the bundler group with 1 update in the / directory: [actionview](https://github.com/rails/rails).


Updates `actionview` from 8.0.2 to 8.0.4.1
- [Release notes](https://github.com/rails/rails/releases)
- [Changelog](https://github.com/rails/rails/blob/v8.1.2.1/actionview/CHANGELOG.md)
- [Commits](rails/rails@v8.0.2...v8.0.4.1)

---
updated-dependencies:
- dependency-name: actionview
  dependency-version: 8.0.4.1
  dependency-type: indirect
  dependency-group: bundler
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [rubygems/release-gem](https://github.com/rubygems/release-gem) from 1.1.4 to 1.2.0.
- [Release notes](https://github.com/rubygems/release-gem/releases)
- [Commits](rubygems/release-gem@e9a6361...6317d8d)

---
updated-dependencies:
- dependency-name: rubygems/release-gem
  dependency-version: 1.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [cucumber](https://github.com/cucumber/cucumber-ruby) from 10.2.0 to 11.0.0.
- [Release notes](https://github.com/cucumber/cucumber-ruby/releases)
- [Changelog](https://github.com/cucumber/cucumber-ruby/blob/main/CHANGELOG.md)
- [Commits](cucumber/cucumber-ruby@v10.2.0...v11.0.0)

---
updated-dependencies:
- dependency-name: cucumber
  dependency-version: 11.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [yard](https://yardoc.org) from 0.9.38 to 0.9.43.

---
updated-dependencies:
- dependency-name: yard
  dependency-version: 0.9.43
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.16.0 to 2.19.0.
- [Release notes](https://github.com/step-security/harden-runner/releases)
- [Commits](step-security/harden-runner@fa2e9d6...8d3c67d)

---
updated-dependencies:
- dependency-name: step-security/harden-runner
  dependency-version: 2.19.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.296.0 to 1.302.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](ruby/setup-ruby@eab2afb...7372622)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.302.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 7.0.0 to 7.1.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](docker/build-push-action@d08e5c3...bcafcac)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [puma](https://github.com/puma/puma) from 7.2.0 to 8.0.0.
- [Release notes](https://github.com/puma/puma/releases)
- [Changelog](https://github.com/puma/puma/blob/main/History.md)
- [Commits](puma/puma@v7.2.0...v8.0.0)

---
updated-dependencies:
- dependency-name: puma
  dependency-version: 8.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [timecop](https://github.com/travisjeffery/timecop) from 0.9.10 to 0.9.11.
- [Changelog](https://github.com/travisjeffery/timecop/blob/master/History.md)
- [Commits](travisjeffery/timecop@v0.9.10...v0.9.11)

---
updated-dependencies:
- dependency-name: timecop
  dependency-version: 0.9.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.302.0 to 1.306.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](ruby/setup-ruby@7372622...c4e5b13)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.306.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [rake](https://github.com/ruby/rake) from 13.3.1 to 13.4.2.
- [Release notes](https://github.com/ruby/rake/releases)
- [Changelog](https://github.com/ruby/rake/blob/master/History.rdoc)
- [Commits](ruby/rake@v13.3.1...v13.4.2)

---
updated-dependencies:
- dependency-name: rake
  dependency-version: 13.4.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
* refactor: Stick cards to the left side of the grid for laptop view

* refactor: Do not cut our background after first screen

* refactor: Stick footer to the bottom of the page

* refactor: Stick menu and logo to right and left top corners of the screen

* refactor: Stick stats block to card bottom; stick timestamp to top right of the card
Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 2.19.0 to 2.19.3.
- [Release notes](https://github.com/step-security/harden-runner/releases)
- [Commits](step-security/harden-runner@8d3c67d...ab7a940)

---
updated-dependencies:
- dependency-name: step-security/harden-runner
  dependency-version: 2.19.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [ruby/setup-ruby](https://github.com/ruby/setup-ruby) from 1.306.0 to 1.307.0.
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](ruby/setup-ruby@c4e5b13...6aaa311)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.307.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 4.9.0 to 5.0.0.
- [Release notes](https://github.com/actions/dependency-review-action/releases)
- [Commits](actions/dependency-review-action@2031cfc...a1d282b)

---
updated-dependencies:
- dependency-name: actions/dependency-review-action
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@github-actions github-actions Bot added proquo: large ProQuo review price tier: large and removed proquo: small ProQuo review price tier: small labels Sep 7, 2026
@nebiyuelias1

Copy link
Copy Markdown
Contributor

Thanks @Lokideos for introducing me to this gem and @bolshakov for the help, hope to contribute more!

bolshakov and others added 16 commits September 8, 2026 17:19
versions, but the gemspec still allowed >= 3.2. Without this, 6.0.0
installs on a Ruby nothing is tested against.
A verify job runs before the release environment gate and fails unless the
pushed tag equals the gemspec version, so a mismatched tag never reaches
approval. The tag already exists when the release task runs, so it only
publishes the gem. The Docker image is tagged latest only for non-prerelease
versions.
The release environment requires a reviewer, and each job that names it asks
for approval separately, so a release needed two clicks. The Docker Hub
credentials now live in the docker-hub environment, which has no reviewers
but is limited to v* tags. The image job still waits on the gem job, so one
approval covers the release.
The gate was skipped for pull requests against main because release and
hotfix branches had already run the suite once against develop. With main as
the only integration branch there is no earlier run to rely on, so every pull
request now goes smoke, approval, full specs, features.

The "Full test suite (automatic)" environment is no longer referenced.
…uide

Covers the new return values of Light#color and Light#state, the symbols on
telemetry events, and Light#lock rejecting string colors.
* chore: Change color and lock state constants to symbols

* refactor: Decouple Admin Panel from gem internals with a helper

* refactor: Introduce color and state parameter types for feature tests
Records main as merged without taking any of its content. The tree is
unchanged.

main carries the v5.8.3 hotfix 25288bb, which gave the Redis metrics key a
TTL equal to the window size in the monolithic data store that 6.0.0 removes.
The decomposed window metrics store evicts buckets older than the window on
every write, so memory is bounded by the window rather than by request volume.
The hotfix is superseded, and a normal merge would only have resurrected the
files 6.0.0 deleted.
@bolshakov
bolshakov marked this pull request as ready for review September 9, 2026 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

proquo: large ProQuo review price tier: large

Projects

None yet

Development

Successfully merging this pull request may close these issues.