Skip to content

Instantly share code, notes, and snippets.

@ryenski
Created March 30, 2026 15:59
Show Gist options
  • Select an option

  • Save ryenski/d4774b327a816d4404ae9ba4eaae8d17 to your computer and use it in GitHub Desktop.

Select an option

Save ryenski/d4774b327a816d4404ae9ba4eaae8d17 to your computer and use it in GitHub Desktop.
Grips codebase tech debt analysis — March 2026

Grips Codebase — Tech Debt Analysis

Generated: March 30, 2026
Codebase size: ~1,118 app files, 274 models, 207 controllers, 264 services, 950 tests


1. Dead / Orphaned Code

These files exist but are never referenced outside themselves. Safe to delete after confirmation.

File Notes
app/jobs/upload_to_gcs_job.rb No callers found anywhere in app or config
app/jobs/process_orders_linnworks_job.rb Only referenced in its own file; Ctdi::* models it depends on are also orphaned
app/models/ctdi.rb + app/models/ctdi/ (5 files) Only called by the orphaned Linnworks job above
app/views/layouts/partials/_gierd_terms_of_use_BAK.html.erb 935-line BAK file; no references found
my_gaps.csv Stray data file committed to repo root

Action: Delete these files. Run rg "UploadToGcsJob\|ProcessOrdersLinnworksJob\|Ctdi::" first to confirm no dynamic dispatch.


2. Deprecated Code Still Running in Production

These are self-described as deprecated/decommissioned but still active.

Gus::ModelProxy (DECOMMISSIONED 2025-10-16)

  • app/models/gus/model_proxy.rb (325 lines) annotated @deprecated DECOMMISSIONED: 2025-10-16
  • app/models/gus/model/inventory.rb annotated # DECOMMISSIONED: 2025-10-16
  • Still called via Gus.models(gierd_customer_id) in 10+ controllers: key_metrics_controller.rb, goal/trends_controller.rb, forecasting/supply_demand_controller.rb, finrec/base_controller.rb, finrec/performances_controller.rb

Finrec::PerformancesController

# TODO: This controller will be deprecated in favor of the Overview controller.

Still routed and functional. Finrec::OverviewController exists in parallel.

Pricing::Offer#status column

Multiple @deprecated annotations across app/models/pricing/offer.rb and app/models/concerns/inventory_item/pricable.rb. Noted as superseded by GUS offer_status, but the column is still referenced in scopes and queries.

target_price field

app/services/pricing/price_history_query.rb:

# TODO: target_price is deprecated and should be removed from this query.
# chart_data_controller_test.rb will need to be updated.

Connection::CatalogChannelsController

Marked as "temporary feature needed during transition to V2 Pricing Engine" and "will be deprecated" — still active.


3. params.require().permit() Anti-pattern (42 Controllers)

The project standard is params.expect(model: [...]) (Rails 8 convention), but 42 controllers still use the old pattern:

app/controllers/connection/linnworkses_controller.rb
app/controllers/connection/shopifies_controller.rb
app/controllers/pricing/strategies_controller.rb
app/controllers/pricing/rules_controller.rb
app/controllers/auction/runs_controller.rb
... (37 more)

Action: Batch migrate to params.expect().


4. Oversized Files

Models (SRP violations)

File Lines Notes
imports/pricing/promo_import.rb 1,179 Single import model
imports/pricing/channel_min_max_import.rb 884 Single import model
account.rb 616 11 TODO/FIXME comments; has ENV vars, demo code, and legacy org migration logic all mixed together
pricing/price_log.rb 476
report_extraction.rb 473

Services (heavy layer for a "vanilla Rails" architecture)

264 service files exist despite the architectural preference to minimize them. Largest:

File Lines
external/provisioning/adapters/airbyte.rb 720
ai/query_processor.rb 548
external/clients/linnworks_api.rb 423
external/provisioning/serializers/airbyte/amazon/serializer.rb 421

Stimulus Controllers (violates "modest JS" principle)

File Lines
combo_box_controller.js 2,524
data_grid_controller.js 1,540
mini_calendar_controller.js 1,102
finrec_form_controller.js 685
csv_upload_controller.js 677
demo_payouts_controller.js 645

These controllers are doing too much. Consider decomposing into smaller, focused controllers.


5. Incomplete Features Committed to Production

These TODOs represent unfinished work that shipped:

File Issue
pricing/comparisons/_save_heart.html.erb 🔥 TODO: Add data-driven functionality
pricing/groups/_form.html.erb TODO: GET THIS WORKING
key_metrics/_form.html.erb TODO: Connect SKU input to the backend
goal/trends/_form.html.erb TODO: Connect SKU input to the backend
pricing/strategies/velocity/_fields.html.erb TODO: Add when with_velocity_fields is ready
pricing/strategies/sellthrough/_fields.html.erb TODO: Add when with_sellthrough_fields is ready
pricing/strategies/agent/_fields.html.erb TODO: Remove this when we activate "agent" as a concept
services/internal/redirect/onboarding.rb TODO: Implement onboarding logic (stub)
finrec/summaries/_net_revenue.html.erb TODO: This is not implemented correctly
layouts/partials/header/_search_form.html.erb Search form not connected to backend

6. Demo / Temporary Code Leaking into Production

File Notes
app/controllers/demo_controller.rb Demo controller with no removal plan
app/views/demo/ Demo views including item_logic_override.html.erb (417 lines)
app/javascript/controllers/demo_payouts_controller.js 645-line JS controller for demo only
app/views/layouts/partials/_head_demo_assets.html.erb Self-describes as ⚠️ deprecated
app/views/layouts/partials/_head.html.erb Contains 🔥 START FIXME: For demo account. Remove when not needed.
app/models/account.rb Demo account logic, FIXME: Remove once demo account is no longer needed

7. ENV Variables in Model Layer

app/models/account.rb directly reads from ENV with a FIXME:

refresh_token: ENV.fetch("LINNWORKS_TOKEN") { Credentials.linnworks.att_token }
# FIXME: should move to connection in db. per account!

Credentials should come from the database-backed connection, not hardcoded ENV vars in the model.


8. Broad Exception Handling

  • 76 files use rescue StandardError or rescue Exception
  • 38 files use bare rescue => e

This makes errors silently swallowed rather than surfaced. Prefer rescuing specific exception classes and always notify Honeybadger.


9. Sleep-based Rate Limiting in Jobs/Services

Multiple jobs and API clients use sleep() for rate limiting instead of Rails' built-in retry mechanisms:

# app/jobs/report_extraction_v2_base.rb
sleep(1 / self.class::RATE_LIMIT)

# app/services/external/provisioning/account.rb
sleep 5

# app/jobs/integration/target/taxonomies/pull_items_batch_job.rb
sleep(3) unless index == sku_batch.size - 1

Risk: Blocks job threads, reducing throughput. Use retry_on with exponential backoff or move to a dedicated rate-limit queue instead.


10. Pundit Authorization Not Consistently Enforced

207 controllers exist, but only ~45 use after_action :verify_authorized. The ApplicationController includes Pundit::Authorization but doesn't set a global after_action :verify_authorized. Controllers must opt in, which creates risk of authorization being accidentally skipped.

Recommendation: Add after_action :verify_authorized to ApplicationController and use skip_after_action in controllers like webhooks/API that legitimately don't need it.


11. Gems in Gemfile Likely Unused or Misplaced

Gem Issue
wicked In production Gemfile; zero usage found in app/ or config/
faker Listed in production group; zero usage outside tests
authentication-zero Listed in production Gemfile; appears to be a generator gem that should be dev-only
irb Listed in production Gemfile; should be dev/test only

Action: Run bundle exec bundler-audit (already in Gemfile) and audit unused gems.


12. API Version Migration Stalled

  • api/v1 routes (shipments, inventories, product_returns) running alongside api/v2 (ingest namespace)
  • Both v1 and v2 controllers active with separate concerns
  • Job naming (report_extraction_v2_base.rb) implies a v1 still existed
  • No documented deprecation timeline for v1

13. Migration Count / Schema Size

  • 308 migrations — the schema is 1,773 lines. Consider squashing migrations.
  • Recent batch of index-only migrations (20260309180000, 20260309180001, 20260317120000) suggests missing indexes were found late; add query analysis to the PR process.

14. Test Coverage Gaps

Area Test Files App Files Gap
Models 207 274 67 untested model files
Overall 950 1,118 ~15% of app files lack a test file

The account.rb model (616 lines, 11 TODO/FIXMEs) is a high-risk untested area. Services particularly lack coverage given 264 service files exist.


Priority Matrix

Priority Item Effort
🔴 High Delete orphaned jobs + Ctdi models Low
🔴 High Remove BAK partial + my_gaps.csv Low
🔴 High Fix Pundit authorization enforcement Medium
🟡 Medium Migrate 42 controllers off params.require Medium
🟡 Medium Clean up demo code and controllers Medium
🟡 Medium Remove/complete deprecated controllers (PerformancesController, CatalogChannelsController) Medium
🟡 Medium Replace sleep() rate limiting with proper job retries Medium
🟡 Medium Move ENV var out of Account model Low
🟢 Low Remove/audit unused gems (wicked, faker, irb) Low
🟢 Low Squash 308 migrations Low
🟢 Low Decompose large Stimulus controllers High
🟢 Low Clean up deprecated Pricing::Offer#status column High
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment