perfgate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +25 -0
  4. data/CHANGELOG.md +18 -0
  5. data/CONTRIBUTING.md +73 -0
  6. data/LICENSE +201 -0
  7. data/NOT_FINALIZED.md +70 -0
  8. data/README.md +86 -0
  9. data/ROADMAP.md +125 -0
  10. data/Rakefile +12 -0
  11. data/SECURITY.md +63 -0
  12. data/docs/README.md +7 -0
  13. data/docs/architecture.md +125 -0
  14. data/docs/compatibility.md +49 -0
  15. data/docs/launch-article.md +97 -0
  16. data/docs/onboarding.md +122 -0
  17. data/docs/telemetry.md +81 -0
  18. data/examples/rails-rspec-app/.github/workflows/baseline.yml +48 -0
  19. data/examples/rails-rspec-app/README.md +38 -0
  20. data/examples/rails-rspec-app/spec/jobs/invoice_job_spec.rb +15 -0
  21. data/examples/rails-rspec-app/spec/requests/checkout_spec.rb +24 -0
  22. data/exe/perfgate +7 -0
  23. data/lib/perfgate/cli/compare_command.rb +91 -0
  24. data/lib/perfgate/cli/run_command.rb +123 -0
  25. data/lib/perfgate/cli/run_comparison_reporter.rb +77 -0
  26. data/lib/perfgate/cli.rb +60 -0
  27. data/lib/perfgate/comparison/deterministic_metric_decision.rb +34 -0
  28. data/lib/perfgate/comparison/diagnostics.rb +70 -0
  29. data/lib/perfgate/comparison/engine.rb +79 -0
  30. data/lib/perfgate/comparison/metric_change.rb +84 -0
  31. data/lib/perfgate/comparison/metric_decision.rb +39 -0
  32. data/lib/perfgate/comparison/statistical_metric_decision.rb +75 -0
  33. data/lib/perfgate/comparison/workload_comparison.rb +98 -0
  34. data/lib/perfgate/config/defaults.rb +70 -0
  35. data/lib/perfgate/config/env_overrides.rb +54 -0
  36. data/lib/perfgate/config/schema.rb +53 -0
  37. data/lib/perfgate/config/validator.rb +64 -0
  38. data/lib/perfgate/config.rb +136 -0
  39. data/lib/perfgate/errors.rb +20 -0
  40. data/lib/perfgate/execution/process_runner.rb +71 -0
  41. data/lib/perfgate/execution/runner.rb +60 -0
  42. data/lib/perfgate/execution/sample_context.rb +66 -0
  43. data/lib/perfgate/fingerprints/compatibility.rb +46 -0
  44. data/lib/perfgate/fingerprints/components.rb +98 -0
  45. data/lib/perfgate/fingerprints/workload_definition.rb +30 -0
  46. data/lib/perfgate/instrumentation/allocations.rb +20 -0
  47. data/lib/perfgate/instrumentation/duration.rb +20 -0
  48. data/lib/perfgate/instrumentation/gc.rb +30 -0
  49. data/lib/perfgate/instrumentation/sql_activity.rb +50 -0
  50. data/lib/perfgate/instrumentation.rb +36 -0
  51. data/lib/perfgate/metrics/.gitkeep +0 -0
  52. data/lib/perfgate/policy/engine.rb +73 -0
  53. data/lib/perfgate/rails/.gitkeep +0 -0
  54. data/lib/perfgate/report/console.rb +57 -0
  55. data/lib/perfgate/report/markdown.rb +101 -0
  56. data/lib/perfgate/reporting/.gitkeep +0 -0
  57. data/lib/perfgate/rspec/discovery.rb +31 -0
  58. data/lib/perfgate/rspec/id_resolver.rb +30 -0
  59. data/lib/perfgate/rspec/workload_builder.rb +48 -0
  60. data/lib/perfgate/rspec.rb +14 -0
  61. data/lib/perfgate/serialization/run_result.rb +58 -0
  62. data/lib/perfgate/statistics/mann_whitney_u.rb +84 -0
  63. data/lib/perfgate/statistics/summary.rb +60 -0
  64. data/lib/perfgate/storage/adapter.rb +24 -0
  65. data/lib/perfgate/storage/archive.rb +69 -0
  66. data/lib/perfgate/storage/filesystem.rb +121 -0
  67. data/lib/perfgate/telemetry/.gitkeep +0 -0
  68. data/lib/perfgate/version.rb +5 -0
  69. data/lib/perfgate/workloads/registry.rb +50 -0
  70. data/lib/perfgate/workloads/workload.rb +26 -0
  71. data/lib/perfgate.rb +46 -0
  72. data/perfgate.gemspec +41 -0
  73. data/schemas/comparison-result-v1.schema.json +7 -0
  74. data/schemas/run-result-v1.schema.json +7 -0
  75. data/sig/perfgate.rbs +4 -0
  76. metadata +139 -0
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perfgate
4
+ module Workloads
5
+ # Collects Workload instances discovered for a run and enforces the
6
+ # uniqueness rule from spec section 9.2: "a duplicate explicit ID is
7
+ # a configuration error".
8
+ class Registry
9
+ include Enumerable
10
+
11
+ class << self
12
+ def instance
13
+ @instance ||= new
14
+ end
15
+
16
+ def reset!
17
+ @instance = new
18
+ end
19
+ end
20
+
21
+ def initialize
22
+ @workloads = {}
23
+ end
24
+
25
+ def register(workload)
26
+ raise Perfgate::WorkloadError, "duplicate workload id: #{workload.id.inspect}" if @workloads.key?(workload.id)
27
+
28
+ @workloads[workload.id] = workload
29
+ end
30
+
31
+ def [](id)
32
+ @workloads[id]
33
+ end
34
+
35
+ def each(&block)
36
+ return enum_for(:each) unless block
37
+
38
+ @workloads.each_value(&block)
39
+ end
40
+
41
+ def ids
42
+ @workloads.keys
43
+ end
44
+
45
+ def clear
46
+ @workloads.clear
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perfgate
4
+ module Workloads
5
+ # A deterministic executable path measured by Baseline (spec section
6
+ # 7). Normally backed by one RSpec example, but the callable is kept
7
+ # generic so the execution engine can be exercised without RSpec.
8
+ class Workload
9
+ attr_reader :id, :samples, :warmup, :metrics
10
+
11
+ def initialize(id:, samples:, warmup:, metrics: [:duration], &block)
12
+ raise ArgumentError, "workload #{id.inspect} requires a block to execute" unless block
13
+
14
+ @id = id
15
+ @samples = samples
16
+ @warmup = warmup
17
+ @metrics = metrics
18
+ @block = block
19
+ end
20
+
21
+ def call
22
+ @block.call
23
+ end
24
+ end
25
+ end
26
+ end
data/lib/perfgate.rb ADDED
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "perfgate/version"
4
+ require_relative "perfgate/errors"
5
+ require_relative "perfgate/config"
6
+ require_relative "perfgate/workloads/registry"
7
+ require_relative "perfgate/execution/sample_context"
8
+
9
+ # Baseline is a CI-native performance assurance tool for Ruby on Rails
10
+ # applications. It converts selected RSpec examples into repeatable
11
+ # performance workloads and compares them against a compatible
12
+ # default-branch baseline to produce a merge-gate decision.
13
+ module Perfgate
14
+ class << self
15
+ # Explicitly marks the block whose execution should be measured by
16
+ # Baseline (spec section 9.1). Outside of a running workload sample
17
+ # (e.g. called directly in a plain unit test) this simply executes
18
+ # the block and returns its value without recording anything.
19
+ def measure(&block)
20
+ context = Execution::SampleContext.current
21
+ return block.call unless context
22
+
23
+ context.measure(&block)
24
+ end
25
+
26
+ # The active configuration, loaded via Config.load or Config.default.
27
+ # `baseline run` assigns this after loading baseline.yml.
28
+ def configuration
29
+ @configuration ||= Config.default
30
+ end
31
+
32
+ attr_writer :configuration
33
+
34
+ # Yields the active configuration for in-code customization, e.g.
35
+ # `Perfgate.configure { |config| config.dataset_fingerprint = -> { ... } }`
36
+ # (spec section 12.3).
37
+ def configure
38
+ yield configuration
39
+ end
40
+
41
+ # The process-wide workload registry that RSpec discovery populates.
42
+ def registry
43
+ Workloads::Registry.instance
44
+ end
45
+ end
46
+ end
data/perfgate.gemspec ADDED
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/perfgate/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "perfgate"
7
+ spec.version = Perfgate::VERSION
8
+ spec.authors = ["Alexander Potrakhov"]
9
+ spec.email = ["bendthe@gmail.com"]
10
+
11
+ spec.summary = "CI-native performance regression assurance for Rails and RSpec."
12
+ spec.description = "Baseline converts selected RSpec examples into repeatable performance " \
13
+ "workloads, measures application-level signals (duration, SQL activity, " \
14
+ "allocations, GC), compares a pull request against a compatible " \
15
+ "default-branch baseline, and produces a clear CI merge-gate decision."
16
+ spec.homepage = "https://github.com/a11ejandro/perfgate"
17
+ spec.license = "Apache-2.0"
18
+ spec.required_ruby_version = ">= 3.1.0"
19
+
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = spec.homepage
22
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
23
+ spec.metadata["rubygems_mfa_required"] = "true"
24
+
25
+ # Specify which files should be added to the gem when it is released.
26
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
+ spec.files = Dir.chdir(__dir__) do
28
+ `git ls-files -z`.split("\x0").reject do |f|
29
+ (File.expand_path(f) == __FILE__) ||
30
+ f.start_with?(*%w[bin/ test/ spec/ features/ spikes/ .git .github appveyor Gemfile])
31
+ end
32
+ end
33
+ spec.bindir = "exe"
34
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
35
+ spec.require_paths = ["lib"]
36
+
37
+ spec.add_dependency "rspec-core", "~> 3.12"
38
+
39
+ # For more information and examples about making a new gem, check out our
40
+ # guide at: https://bundler.io/guides/creating_gem.html
41
+ end
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://baseline.dev/schemas/comparison-result-v1.schema.json",
4
+ "title": "Baseline Comparison Result v1",
5
+ "description": "Placeholder schema. To be defined per section 14.2 of the technical specification.",
6
+ "type": "object"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://baseline.dev/schemas/run-result-v1.schema.json",
4
+ "title": "Baseline Run Result v1",
5
+ "description": "Placeholder schema. To be defined per section 14.1 of the technical specification.",
6
+ "type": "object"
7
+ }
data/sig/perfgate.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Perfgate
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: perfgate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Potrakhov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2026-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.12'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.12'
27
+ description: Baseline converts selected RSpec examples into repeatable performance
28
+ workloads, measures application-level signals (duration, SQL activity, allocations,
29
+ GC), compares a pull request against a compatible default-branch baseline, and produces
30
+ a clear CI merge-gate decision.
31
+ email:
32
+ - bendthe@gmail.com
33
+ executables:
34
+ - perfgate
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - ".rspec"
39
+ - ".rubocop.yml"
40
+ - CHANGELOG.md
41
+ - CONTRIBUTING.md
42
+ - LICENSE
43
+ - NOT_FINALIZED.md
44
+ - README.md
45
+ - ROADMAP.md
46
+ - Rakefile
47
+ - SECURITY.md
48
+ - docs/README.md
49
+ - docs/architecture.md
50
+ - docs/compatibility.md
51
+ - docs/launch-article.md
52
+ - docs/onboarding.md
53
+ - docs/telemetry.md
54
+ - examples/rails-rspec-app/.github/workflows/baseline.yml
55
+ - examples/rails-rspec-app/README.md
56
+ - examples/rails-rspec-app/spec/jobs/invoice_job_spec.rb
57
+ - examples/rails-rspec-app/spec/requests/checkout_spec.rb
58
+ - exe/perfgate
59
+ - lib/perfgate.rb
60
+ - lib/perfgate/cli.rb
61
+ - lib/perfgate/cli/compare_command.rb
62
+ - lib/perfgate/cli/run_command.rb
63
+ - lib/perfgate/cli/run_comparison_reporter.rb
64
+ - lib/perfgate/comparison/deterministic_metric_decision.rb
65
+ - lib/perfgate/comparison/diagnostics.rb
66
+ - lib/perfgate/comparison/engine.rb
67
+ - lib/perfgate/comparison/metric_change.rb
68
+ - lib/perfgate/comparison/metric_decision.rb
69
+ - lib/perfgate/comparison/statistical_metric_decision.rb
70
+ - lib/perfgate/comparison/workload_comparison.rb
71
+ - lib/perfgate/config.rb
72
+ - lib/perfgate/config/defaults.rb
73
+ - lib/perfgate/config/env_overrides.rb
74
+ - lib/perfgate/config/schema.rb
75
+ - lib/perfgate/config/validator.rb
76
+ - lib/perfgate/errors.rb
77
+ - lib/perfgate/execution/process_runner.rb
78
+ - lib/perfgate/execution/runner.rb
79
+ - lib/perfgate/execution/sample_context.rb
80
+ - lib/perfgate/fingerprints/compatibility.rb
81
+ - lib/perfgate/fingerprints/components.rb
82
+ - lib/perfgate/fingerprints/workload_definition.rb
83
+ - lib/perfgate/instrumentation.rb
84
+ - lib/perfgate/instrumentation/allocations.rb
85
+ - lib/perfgate/instrumentation/duration.rb
86
+ - lib/perfgate/instrumentation/gc.rb
87
+ - lib/perfgate/instrumentation/sql_activity.rb
88
+ - lib/perfgate/metrics/.gitkeep
89
+ - lib/perfgate/policy/engine.rb
90
+ - lib/perfgate/rails/.gitkeep
91
+ - lib/perfgate/report/console.rb
92
+ - lib/perfgate/report/markdown.rb
93
+ - lib/perfgate/reporting/.gitkeep
94
+ - lib/perfgate/rspec.rb
95
+ - lib/perfgate/rspec/discovery.rb
96
+ - lib/perfgate/rspec/id_resolver.rb
97
+ - lib/perfgate/rspec/workload_builder.rb
98
+ - lib/perfgate/serialization/run_result.rb
99
+ - lib/perfgate/statistics/mann_whitney_u.rb
100
+ - lib/perfgate/statistics/summary.rb
101
+ - lib/perfgate/storage/adapter.rb
102
+ - lib/perfgate/storage/archive.rb
103
+ - lib/perfgate/storage/filesystem.rb
104
+ - lib/perfgate/telemetry/.gitkeep
105
+ - lib/perfgate/version.rb
106
+ - lib/perfgate/workloads/registry.rb
107
+ - lib/perfgate/workloads/workload.rb
108
+ - perfgate.gemspec
109
+ - schemas/comparison-result-v1.schema.json
110
+ - schemas/run-result-v1.schema.json
111
+ - sig/perfgate.rbs
112
+ homepage: https://github.com/a11ejandro/perfgate
113
+ licenses:
114
+ - Apache-2.0
115
+ metadata:
116
+ homepage_uri: https://github.com/a11ejandro/perfgate
117
+ source_code_uri: https://github.com/a11ejandro/perfgate
118
+ changelog_uri: https://github.com/a11ejandro/perfgate/blob/main/CHANGELOG.md
119
+ rubygems_mfa_required: 'true'
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: 3.1.0
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubygems_version: 3.4.10
136
+ signing_key:
137
+ specification_version: 4
138
+ summary: CI-native performance regression assurance for Rails and RSpec.
139
+ test_files: []