code_sunset 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 (71) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +242 -0
  4. data/Rakefile +6 -0
  5. data/app/assets/images/code_sunset/.keep +0 -0
  6. data/app/assets/images/code_sunset/logo-dark.png +0 -0
  7. data/app/assets/images/code_sunset/logo-light.png +0 -0
  8. data/app/assets/images/code_sunset/topography.svg +1 -0
  9. data/app/assets/javascripts/code_sunset/application.js +179 -0
  10. data/app/assets/javascripts/code_sunset/vendor/chart.umd.min.js +14 -0
  11. data/app/assets/stylesheets/code_sunset/application.css +1075 -0
  12. data/app/controllers/code_sunset/application_controller.rb +50 -0
  13. data/app/controllers/code_sunset/dashboard_controller.rb +12 -0
  14. data/app/controllers/code_sunset/features_controller.rb +62 -0
  15. data/app/controllers/code_sunset/removal_candidates_controller.rb +9 -0
  16. data/app/controllers/concerns/.keep +0 -0
  17. data/app/helpers/code_sunset/application_helper.rb +244 -0
  18. data/app/jobs/code_sunset/aggregate_daily_rollups_job.rb +48 -0
  19. data/app/jobs/code_sunset/application_job.rb +4 -0
  20. data/app/jobs/code_sunset/cleanup_events_job.rb +10 -0
  21. data/app/jobs/code_sunset/evaluate_alerts_job.rb +15 -0
  22. data/app/jobs/code_sunset/flush_buffered_events_job.rb +9 -0
  23. data/app/jobs/code_sunset/persist_event_job.rb +9 -0
  24. data/app/mailers/code_sunset/application_mailer.rb +6 -0
  25. data/app/models/code_sunset/alert_delivery.rb +14 -0
  26. data/app/models/code_sunset/application_record.rb +5 -0
  27. data/app/models/code_sunset/daily_rollup.rb +31 -0
  28. data/app/models/code_sunset/event.rb +190 -0
  29. data/app/models/code_sunset/feature.rb +33 -0
  30. data/app/models/concerns/.keep +0 -0
  31. data/app/views/code_sunset/dashboard/index.html.erb +123 -0
  32. data/app/views/code_sunset/features/index.html.erb +88 -0
  33. data/app/views/code_sunset/features/show.html.erb +266 -0
  34. data/app/views/code_sunset/removal_candidates/index.html.erb +118 -0
  35. data/app/views/code_sunset/shared/_filter_bar.html.erb +81 -0
  36. data/app/views/layouts/code_sunset/application.html.erb +57 -0
  37. data/bin/rails +26 -0
  38. data/code_sunset.gemspec +35 -0
  39. data/config/routes.rb +5 -0
  40. data/db/migrate/20260330000000_create_code_sunset_tables.rb +62 -0
  41. data/db/migrate/20260331000000_harden_code_sunset_reliability.rb +39 -0
  42. data/lib/code_sunset/alert_dispatcher.rb +103 -0
  43. data/lib/code_sunset/analytics_filters.rb +59 -0
  44. data/lib/code_sunset/configuration.rb +104 -0
  45. data/lib/code_sunset/context.rb +49 -0
  46. data/lib/code_sunset/controller_context.rb +23 -0
  47. data/lib/code_sunset/engine.rb +24 -0
  48. data/lib/code_sunset/event_buffer.rb +28 -0
  49. data/lib/code_sunset/event_ingestor.rb +57 -0
  50. data/lib/code_sunset/event_payload.rb +79 -0
  51. data/lib/code_sunset/feature_query.rb +69 -0
  52. data/lib/code_sunset/feature_snapshot.rb +14 -0
  53. data/lib/code_sunset/feature_usage_series.rb +59 -0
  54. data/lib/code_sunset/identity_hash.rb +9 -0
  55. data/lib/code_sunset/instrumentation.rb +17 -0
  56. data/lib/code_sunset/job_context.rb +17 -0
  57. data/lib/code_sunset/removal_candidate_query.rb +17 -0
  58. data/lib/code_sunset/removal_prompt_builder.rb +331 -0
  59. data/lib/code_sunset/score_calculator.rb +83 -0
  60. data/lib/code_sunset/status_engine.rb +38 -0
  61. data/lib/code_sunset/subscriber.rb +24 -0
  62. data/lib/code_sunset/version.rb +3 -0
  63. data/lib/code_sunset.rb +109 -0
  64. data/lib/generators/code_sunset/eject_ui/eject_ui_generator.rb +33 -0
  65. data/lib/generators/code_sunset/initializer/initializer_generator.rb +13 -0
  66. data/lib/generators/code_sunset/initializer/templates/code_sunset.rb +34 -0
  67. data/lib/generators/code_sunset/install/install_generator.rb +23 -0
  68. data/lib/generators/code_sunset/migration/migration_generator.rb +21 -0
  69. data/lib/generators/code_sunset/migration/templates/create_code_sunset_tables.rb +75 -0
  70. data/lib/tasks/code_sunset_tasks.rake +21 -0
  71. metadata +185 -0
@@ -0,0 +1,109 @@
1
+ require "active_support"
2
+ require "active_support/core_ext/hash/deep_merge"
3
+ require "active_support/core_ext/hash/keys"
4
+ require "active_support/core_ext/integer/time"
5
+ require "active_support/core_ext/object/blank"
6
+ require "active_support/core_ext/object/try"
7
+ require "digest"
8
+ require "json"
9
+ require "logger"
10
+ require "net/http"
11
+ require "uri"
12
+
13
+ require "code_sunset/version"
14
+ require "code_sunset/configuration"
15
+ require "code_sunset/context"
16
+ require "code_sunset/controller_context"
17
+ require "code_sunset/job_context"
18
+ require "code_sunset/event_buffer"
19
+ require "code_sunset/analytics_filters"
20
+ require "code_sunset/event_payload"
21
+ require "code_sunset/instrumentation"
22
+ require "code_sunset/event_ingestor"
23
+ require "code_sunset/identity_hash"
24
+ require "code_sunset/feature_snapshot"
25
+ require "code_sunset/status_engine"
26
+ require "code_sunset/score_calculator"
27
+ require "code_sunset/feature_query"
28
+ require "code_sunset/removal_candidate_query"
29
+ require "code_sunset/feature_usage_series"
30
+ require "code_sunset/removal_prompt_builder"
31
+ require "code_sunset/alert_dispatcher"
32
+ require "code_sunset/subscriber"
33
+ require "code_sunset/engine"
34
+
35
+ module CodeSunset
36
+ class << self
37
+ def configuration
38
+ @configuration ||= Configuration.new
39
+ end
40
+
41
+ def configure
42
+ yield(configuration)
43
+ end
44
+
45
+ def reset_configuration!
46
+ @configuration = Configuration.new
47
+ end
48
+
49
+ def enabled?
50
+ configuration.enabled
51
+ end
52
+
53
+ def event_buffer
54
+ @event_buffer ||= CodeSunset::EventBuffer.new
55
+ end
56
+
57
+ def hit(feature_key, **attrs)
58
+ Instrumentation.hit(feature_key, **attrs)
59
+ end
60
+
61
+ def track(feature_key, **attrs)
62
+ hit(feature_key, **attrs)
63
+ return unless block_given?
64
+
65
+ yield
66
+ end
67
+
68
+ def with_context(**context)
69
+ return unless block_given?
70
+
71
+ Context.with(context) { yield }
72
+ end
73
+
74
+ def register(feature_key, **attrs)
75
+ return unless enabled?
76
+ return unless defined?(CodeSunset::Feature)
77
+
78
+ safe_execute("register #{feature_key}") do
79
+ feature = CodeSunset::Feature.find_or_initialize_by(key: feature_key.to_s)
80
+ feature.assign_attributes(attrs.compact)
81
+ feature.save!
82
+ feature
83
+ end
84
+ end
85
+
86
+ def removal_candidates(filters = {})
87
+ return [] unless defined?(CodeSunset::RemovalCandidateQuery)
88
+
89
+ CodeSunset::RemovalCandidateQuery.new(filters).call
90
+ end
91
+
92
+ def logger
93
+ return Rails.logger if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
94
+
95
+ @logger ||= Logger.new($stdout)
96
+ end
97
+
98
+ def log_error(message, error)
99
+ logger.error("[code_sunset] #{message}: #{error.class}: #{error.message}")
100
+ end
101
+
102
+ def safe_execute(description = "operation")
103
+ yield
104
+ rescue StandardError => error
105
+ log_error(description, error)
106
+ nil
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,33 @@
1
+ require "rails/generators/base"
2
+
3
+ module CodeSunset
4
+ module Generators
5
+ class EjectUiGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("../../../..", __dir__)
7
+
8
+ UI_FILES = {
9
+ "app/assets/javascripts/code_sunset/application.js" => "app/assets/javascripts/code_sunset/application.js",
10
+ "app/assets/javascripts/code_sunset/vendor/chart.umd.min.js" => "app/assets/javascripts/code_sunset/vendor/chart.umd.min.js",
11
+ "app/helpers/code_sunset/application_helper.rb" => "app/helpers/code_sunset/application_helper.rb",
12
+ "app/views/layouts/code_sunset/application.html.erb" => "app/views/layouts/code_sunset/application.html.erb",
13
+ "app/views/code_sunset/dashboard/index.html.erb" => "app/views/code_sunset/dashboard/index.html.erb",
14
+ "app/views/code_sunset/features/index.html.erb" => "app/views/code_sunset/features/index.html.erb",
15
+ "app/views/code_sunset/features/show.html.erb" => "app/views/code_sunset/features/show.html.erb",
16
+ "app/views/code_sunset/removal_candidates/index.html.erb" => "app/views/code_sunset/removal_candidates/index.html.erb",
17
+ "app/assets/stylesheets/code_sunset/application.css" => "app/assets/stylesheets/code_sunset/application.css"
18
+ }.freeze
19
+
20
+ desc "Copies the Code Sunset dashboard UI into the host app for customization."
21
+
22
+ def copy_ui_files
23
+ UI_FILES.each do |source, destination|
24
+ copy_file source, destination
25
+ end
26
+ end
27
+
28
+ def show_next_steps
29
+ say_status :ejected, "Host app copies now override the engine UI. Customize them freely and mount the engine anywhere you like.", :green
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ require "rails/generators/base"
2
+
3
+ module CodeSunset
4
+ module Generators
5
+ class InitializerGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ def copy_initializer
9
+ template "code_sunset.rb", "config/initializers/code_sunset.rb"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ CodeSunset.configure do |config|
2
+ config.enabled = true
3
+ config.environment = Rails.env
4
+ config.async = true
5
+ config.sample_rate = 1.0
6
+ config.app_version = ENV["CODE_SUNSET_APP_VERSION"] || ENV["APP_VERSION"] || ENV["GIT_SHA"]
7
+ config.identity_fields = %i[user_id org_id]
8
+ config.hash_identity = false
9
+ config.event_retention_days = 90
10
+ config.enqueue_failure_policy = :drop
11
+ config.enqueue_buffer_size = 1000
12
+ config.alert_cooldown = 24.hours
13
+
14
+ # Return true to allow dashboard access.
15
+ config.dashboard_authorizer = ->(controller) { controller.respond_to?(:current_user) && controller.current_user.present? }
16
+
17
+ # Optional business-domain hooks.
18
+ # config.plan_resolver = ->(org_id, metadata, _payload) { metadata[:plan] }
19
+ # config.internal_org_resolver = ->(org_id, _metadata, _payload) { InternalOrg.exists?(id: org_id) }
20
+ # config.paid_org_resolver = ->(org_id, _metadata, _payload) { Account.find_by(id: org_id)&.paid? }
21
+
22
+ # Optional custom metadata filters for the admin panel.
23
+ # config.custom_filters = {
24
+ # region: { label: "Region", type: :string, metadata_key: "region" },
25
+ # beta_opt_in: { label: "Beta Opt-In", type: :boolean, metadata_key: "beta_opt_in" },
26
+ # account_tier: { label: "Account Tier", type: :select, metadata_key: "tier", options: [["Free", "free"], ["Pro", "pro"]] }
27
+ # }
28
+ # config.alert_webhook_url = ENV["CODE_SUNSET_WEBHOOK_URL"]
29
+ # config.slack_webhook_url = ENV["CODE_SUNSET_SLACK_WEBHOOK_URL"]
30
+
31
+ # Use :memory_buffer only for best-effort temporary queue outages.
32
+ # Buffered events stay in-process and must be flushed by a scheduled job/task.
33
+ # config.enqueue_failure_policy = :memory_buffer
34
+ end
@@ -0,0 +1,23 @@
1
+ require "rails/generators/base"
2
+
3
+ module CodeSunset
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ class_option :eject_ui, type: :boolean, default: false, desc: "Copy the engine dashboard layout, views, helper, and stylesheet into the host app."
7
+
8
+ def install_initializer
9
+ invoke "code_sunset:initializer"
10
+ end
11
+
12
+ def install_migration
13
+ invoke "code_sunset:migration"
14
+ end
15
+
16
+ def install_ui
17
+ return unless options[:eject_ui]
18
+
19
+ invoke "code_sunset:eject_ui"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ require "rails/generators"
2
+ require "rails/generators/active_record"
3
+ require "rails/generators/migration"
4
+
5
+ module CodeSunset
6
+ module Generators
7
+ class MigrationGenerator < Rails::Generators::Base
8
+ include Rails::Generators::Migration
9
+
10
+ source_root File.expand_path("templates", __dir__)
11
+
12
+ def copy_migration
13
+ migration_template "create_code_sunset_tables.rb", "db/migrate/create_code_sunset_tables.rb"
14
+ end
15
+
16
+ def self.next_migration_number(dirname)
17
+ ActiveRecord::Generators::Base.next_migration_number(dirname)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,75 @@
1
+ class CreateCodeSunsetTables < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :code_sunset_features do |t|
4
+ t.string :key, null: false
5
+ t.string :owner
6
+ t.text :description
7
+ t.string :status
8
+ t.integer :sunset_after_days, null: false, default: 90
9
+ t.integer :remove_after_days_unused, null: false, default: 60
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :code_sunset_features, :key, unique: true
14
+ add_index :code_sunset_features, :status
15
+
16
+ create_table :code_sunset_events do |t|
17
+ t.string :feature_key, null: false
18
+ t.datetime :occurred_at, null: false
19
+ t.bigint :user_id
20
+ t.bigint :org_id
21
+ t.string :hashed_user_id
22
+ t.string :hashed_org_id
23
+ t.string :request_id
24
+ t.string :source
25
+ t.string :request_path
26
+ t.string :controller
27
+ t.string :action
28
+ t.string :job_class
29
+ t.string :app_env, null: false
30
+ t.string :app_version
31
+ t.string :plan
32
+ t.boolean :internal_org
33
+ t.boolean :paid_org
34
+ t.jsonb :metadata, null: false, default: {}
35
+ t.timestamps
36
+ end
37
+
38
+ add_index :code_sunset_events, :feature_key
39
+ add_index :code_sunset_events, :occurred_at
40
+ add_index :code_sunset_events, [:feature_key, :occurred_at]
41
+ add_index :code_sunset_events, :user_id
42
+ add_index :code_sunset_events, :org_id
43
+ add_index :code_sunset_events, :hashed_user_id
44
+ add_index :code_sunset_events, :hashed_org_id
45
+ add_index :code_sunset_events, :app_env
46
+ add_index :code_sunset_events, :plan
47
+ add_index :code_sunset_events, :metadata, using: :gin
48
+
49
+ create_table :code_sunset_daily_rollups do |t|
50
+ t.string :feature_key, null: false
51
+ t.string :app_env
52
+ t.date :day, null: false
53
+ t.integer :hits_count, null: false, default: 0
54
+ t.integer :unique_users_count, null: false, default: 0
55
+ t.integer :unique_orgs_count, null: false, default: 0
56
+ t.datetime :last_seen_at
57
+ t.timestamps
58
+ end
59
+
60
+ add_index :code_sunset_daily_rollups, [:feature_key, :app_env, :day], unique: true, name: "index_code_sunset_rollups_on_feature_env_day"
61
+ add_index :code_sunset_daily_rollups, :day
62
+
63
+ create_table :code_sunset_alert_deliveries do |t|
64
+ t.string :feature_key, null: false
65
+ t.string :status, null: false
66
+ t.string :alert_kind, null: false
67
+ t.datetime :delivered_at, null: false
68
+ t.jsonb :payload, null: false, default: {}
69
+ t.timestamps
70
+ end
71
+
72
+ add_index :code_sunset_alert_deliveries, [:feature_key, :status, :alert_kind, :delivered_at], name: "index_code_sunset_alerts_on_feature_status_kind_time"
73
+ add_index :code_sunset_alert_deliveries, :delivered_at
74
+ end
75
+ end
@@ -0,0 +1,21 @@
1
+ namespace :code_sunset do
2
+ desc "Aggregate raw events into daily rollups"
3
+ task aggregate_rollups: :environment do
4
+ CodeSunset::AggregateDailyRollupsJob.perform_now
5
+ end
6
+
7
+ desc "Clean up raw events older than the configured retention window"
8
+ task cleanup_events: :environment do
9
+ CodeSunset::CleanupEventsJob.perform_now
10
+ end
11
+
12
+ desc "Evaluate alerts for deprecated features"
13
+ task evaluate_alerts: :environment do
14
+ CodeSunset::EvaluateAlertsJob.perform_now
15
+ end
16
+
17
+ desc "Flush buffered events when enqueue_failure_policy is :memory_buffer"
18
+ task flush_buffer: :environment do
19
+ CodeSunset::FlushBufferedEventsJob.perform_now
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: code_sunset
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - sdglhm
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-03-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7.1'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '9.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '7.1'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '9.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: pg
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.6'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.6'
47
+ - !ruby/object:Gem::Dependency
48
+ name: puma
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '7.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '7.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: propshaft
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '1.0'
68
+ - - "<"
69
+ - !ruby/object:Gem::Version
70
+ version: '2.0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '1.0'
78
+ - - "<"
79
+ - !ruby/object:Gem::Version
80
+ version: '2.0'
81
+ description: Track legacy code usage, aggregate removal signals, and review everything
82
+ in a mounted Rails engine dashboard.
83
+ email:
84
+ - hello@sdglhm.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - MIT-LICENSE
90
+ - README.md
91
+ - Rakefile
92
+ - app/assets/images/code_sunset/.keep
93
+ - app/assets/images/code_sunset/logo-dark.png
94
+ - app/assets/images/code_sunset/logo-light.png
95
+ - app/assets/images/code_sunset/topography.svg
96
+ - app/assets/javascripts/code_sunset/application.js
97
+ - app/assets/javascripts/code_sunset/vendor/chart.umd.min.js
98
+ - app/assets/stylesheets/code_sunset/application.css
99
+ - app/controllers/code_sunset/application_controller.rb
100
+ - app/controllers/code_sunset/dashboard_controller.rb
101
+ - app/controllers/code_sunset/features_controller.rb
102
+ - app/controllers/code_sunset/removal_candidates_controller.rb
103
+ - app/controllers/concerns/.keep
104
+ - app/helpers/code_sunset/application_helper.rb
105
+ - app/jobs/code_sunset/aggregate_daily_rollups_job.rb
106
+ - app/jobs/code_sunset/application_job.rb
107
+ - app/jobs/code_sunset/cleanup_events_job.rb
108
+ - app/jobs/code_sunset/evaluate_alerts_job.rb
109
+ - app/jobs/code_sunset/flush_buffered_events_job.rb
110
+ - app/jobs/code_sunset/persist_event_job.rb
111
+ - app/mailers/code_sunset/application_mailer.rb
112
+ - app/models/code_sunset/alert_delivery.rb
113
+ - app/models/code_sunset/application_record.rb
114
+ - app/models/code_sunset/daily_rollup.rb
115
+ - app/models/code_sunset/event.rb
116
+ - app/models/code_sunset/feature.rb
117
+ - app/models/concerns/.keep
118
+ - app/views/code_sunset/dashboard/index.html.erb
119
+ - app/views/code_sunset/features/index.html.erb
120
+ - app/views/code_sunset/features/show.html.erb
121
+ - app/views/code_sunset/removal_candidates/index.html.erb
122
+ - app/views/code_sunset/shared/_filter_bar.html.erb
123
+ - app/views/layouts/code_sunset/application.html.erb
124
+ - bin/rails
125
+ - code_sunset.gemspec
126
+ - config/routes.rb
127
+ - db/migrate/20260330000000_create_code_sunset_tables.rb
128
+ - db/migrate/20260331000000_harden_code_sunset_reliability.rb
129
+ - lib/code_sunset.rb
130
+ - lib/code_sunset/alert_dispatcher.rb
131
+ - lib/code_sunset/analytics_filters.rb
132
+ - lib/code_sunset/configuration.rb
133
+ - lib/code_sunset/context.rb
134
+ - lib/code_sunset/controller_context.rb
135
+ - lib/code_sunset/engine.rb
136
+ - lib/code_sunset/event_buffer.rb
137
+ - lib/code_sunset/event_ingestor.rb
138
+ - lib/code_sunset/event_payload.rb
139
+ - lib/code_sunset/feature_query.rb
140
+ - lib/code_sunset/feature_snapshot.rb
141
+ - lib/code_sunset/feature_usage_series.rb
142
+ - lib/code_sunset/identity_hash.rb
143
+ - lib/code_sunset/instrumentation.rb
144
+ - lib/code_sunset/job_context.rb
145
+ - lib/code_sunset/removal_candidate_query.rb
146
+ - lib/code_sunset/removal_prompt_builder.rb
147
+ - lib/code_sunset/score_calculator.rb
148
+ - lib/code_sunset/status_engine.rb
149
+ - lib/code_sunset/subscriber.rb
150
+ - lib/code_sunset/version.rb
151
+ - lib/generators/code_sunset/eject_ui/eject_ui_generator.rb
152
+ - lib/generators/code_sunset/initializer/initializer_generator.rb
153
+ - lib/generators/code_sunset/initializer/templates/code_sunset.rb
154
+ - lib/generators/code_sunset/install/install_generator.rb
155
+ - lib/generators/code_sunset/migration/migration_generator.rb
156
+ - lib/generators/code_sunset/migration/templates/create_code_sunset_tables.rb
157
+ - lib/tasks/code_sunset_tasks.rake
158
+ homepage: https://sdglhm.com
159
+ licenses:
160
+ - MIT
161
+ metadata:
162
+ homepage_uri: https://sdglhm.com
163
+ source_code_uri: https://github.com/sdglhm/code_sunset
164
+ changelog_uri: https://github.com/sdglhm/code_sunset/blob/main/README.md
165
+ bug_tracker_uri: https://github.com/sdglhm/code_sunset/issues
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ requirements: []
181
+ rubygems_version: 3.4.10
182
+ signing_key:
183
+ specification_version: 4
184
+ summary: Runtime-aware deprecation intelligence for Rails.
185
+ test_files: []