The existing "Code Review" feature provides AI-powered code analysis before deployments. It's fully implemented but triple-gated behind beta_features?, closed_beta_code_reviews_allowed?, and ai_code_review_allowed? -- no customer has ever seen it. We're rebranding it to "Guard Rails" and expanding it from a single AI check into a configurable pre-deployment safety layer with multiple check types.
Since no customer has used the feature, we can freely rename tables, models, routes, and UI without backwards compatibility concerns.
beta_features? + closed_beta_guard_rails_allowed? + guard_rails_allowed?). Only gradually open up.guard_rails_* for clean breakGuard Rails gets its own entry in the project sidebar, between "Automatic Deployments" and "Build Pipeline":
Deployments
Servers & Groups
Config Files
Environment Variables
Excluded Files
Integrations
SSH Commands
Automatic Deployments
► Guard Rails ← NEW
Build Pipeline
Insights
Settings
┌─────────────────────────────────────────────────────────────┐
│ Guard Rails [+ Add Guard Rail] │
├─────────────────────────────────────────────────────────────┤
│ │
│ ℹ️ Guard Rails are pre-deployment checks you can run │
│ before deploying. Configure the checks below, then │
│ trigger them from the deployment form. │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 🔍 AI Code Review [Enabled] ✓ │ │
│ │ AI-powered analysis of your code changes for │ │
│ │ security, performance, and quality issues. │ │
│ │ Mode: Warn only [Edit] │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 🌿 Branch Restriction [Enabled] ✓ │ │
│ │ Only allow deployments from approved branches. │ │
│ │ Allowed: main, release/* [Edit] │ │
│ │ Mode: Block deployment │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 🔒 Env Variable Check [Disabled] │ │
│ │ Verify required environment variables are set. │ │
│ │ [Edit] │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Each rule card shows:
┌─────────────────────────────────────────────────────────────┐
│ New Guard Rail │
├─────────────────────────────────────────────────────────────┤
│ │
│ Type: [AI Code Review ▼] │
│ [Branch Restriction ] │
│ │
│ ── Branch Restriction Settings ── │
│ │
│ Mode: (•) Only allow these branches (allowlist) │
│ ( ) Block these branches (blocklist) │
│ │
│ Branches: [ main, release/*, hotfix/* ] │
│ (comma-separated, supports * wildcards) │
│ │
│ If check fails: │
│ (•) Block deployment │
│ ( ) Warn only (allow deployment to proceed) │
│ │
│ [Cancel] [Save Guard Rail] │
└─────────────────────────────────────────────────────────────┘
The existing "Code Review" section becomes "Guard Rails". It's shown when the project has at least one enabled guard rail rule:
┌─────────────────────────────────────────────────────────────┐
│ New Deployment │
├─────────────────────────────────────────────────────────────┤
│ │
│ Server: [Production (main) ▼] │
│ From: [abc1234] ───────► To: [def5678] │
│ │
│ ── Guard Rails ────────────────────────────────────────── │
│ │ │ │
│ │ ✦ Run pre-deployment checks on your code changes │ │
│ │ 2 checks configured · 47 checks remaining today │ │
│ │ │ │
│ │ [ ✦ Run Guard Rails ] [ Deploy ▶ ] │ │
│ │ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
After clicking "Run Guard Rails", the user sees results for ALL configured checks:
┌─────────────────────────────────────────────────────────────┐
│ Guard Rails Results │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌── Check Results ───────────────────────────────────┐ │
│ │ │ │
│ │ ✅ Branch Restriction PASSED │ │
│ │ Deploying from 'main' — branch is allowed │ │
│ │ │ │
│ │ 🔄 AI Code Review ANALYZING... │ │
│ │ ████████░░░░░░░░ 55% │ │
│ │ Analyzing code changes... │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Waiting for all checks to complete... │
│ │
│ [Back to Deployment] │
└─────────────────────────────────────────────────────────────┘
Once all checks complete:
┌─────────────────────────────────────────────────────────────┐
│ Guard Rails Results │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌── Check Results ───────────────────────────────────┐ │
│ │ │ │
│ │ ✅ Branch Restriction PASSED │ │
│ │ Deploying from 'main' — branch is allowed │ │
│ │ │ │
│ │ ⚠️ AI Code Review Score: 72 / 100 │ │
│ │ 2 high severity findings, 3 medium │ │
│ │ [View Full Report ▶] │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ⚠️ Guard Rails passed with warnings. │
│ Review the findings before deploying. │
│ │
│ [Back to Deployment] [Run Deployment ▶] │
└─────────────────────────────────────────────────────────────┘
If a blocking check fails:
│ ❌ Branch Restriction BLOCKED │
│ Branch 'feature/experiment' is not allowed. │
│ Allowed branches: main, release/* │
│ │
│ ❌ Deployment blocked by Guard Rails. │
│ Fix the issues above before deploying. │
│ │
│ [Back to Deployment] │
Configure (once) Deploy (each time)
───────────────── ──────────────────
Project Sidebar New Deployment Form
└─► Guard Rails Settings ├─► [Run Guard Rails] (opt-in)
├─► Add rules │ └─► Results page
├─► Enable/disable │ ├─► All pass → [Run Deployment]
├─► Set blocking/warn │ ├─► Warn → [Run Deployment] (proceed anyway)
└─► Configure per type │ └─► Blocked → must fix first
└─► [Deploy] (skip guard rails entirely)
Mechanical rename across the entire codebase. The AI code review becomes one "type" of guard rail check.
New file: db/migrate/TIMESTAMP_rename_code_reviews_to_guard_rail_checks.rb
rename_table :code_reviews, :guard_rail_checksadd_column :guard_rail_checks, :check_type, :string, default: 'ai_code_review', null: false, after: :idadd_index :guard_rail_checks, :check_type, length: 191rename_table :code_review_usages, :guard_rail_check_usagesrename_column :guard_rail_check_usages, :code_review_id, :guard_rail_check_idSafe to use rename_table -- these are NOT in the Lhm-required large tables list.
| Old | New | Notes |
|---|---|---|
app/models/code_review.rb | app/models/guard_rail_check.rb | Class GuardRailCheck, add check_type validation, rename has_one :code_review_usage -> has_one :guard_rail_check_usage |
app/models/code_review_usage.rb | app/models/guard_rail_check_usage.rb | Class GuardRailCheckUsage, rename belongs_to :code_review -> belongs_to :guard_rail_check |
| Old | New |
|---|---|
app/controllers/deployments/code_review_controller.rb | app/controllers/deployments/guard_rails_controller.rb |
Class: Deployments::GuardRailsController. Update all internal references.
| Old | New |
|---|---|
app/jobs/generate_code_review_job.rb | app/jobs/generate_guard_rail_check_job.rb |
Class: GenerateGuardRailCheckJob. Keep Ai::CodeReviewService name (it's specific to AI reviews, correct as-is).
# config/routes.rb - replace lines 168-170
get :guard_rails, to: 'deployments/guard_rails#index', on: :member
delete :guard_rails, to: 'deployments/guard_rails#destroy', on: :member
post 'guard_rails/feedback', to: 'deployments/guard_rails#feedback', on: :member
app/models/account.rb)Rename 6 methods:
code_review_allowed? -> guard_rails_allowed?closed_beta_code_reviews_allowed? -> closed_beta_guard_rails_allowed?daily_code_review_limit -> daily_guard_rail_limitcode_review_daily_limit_reached? -> guard_rail_daily_limit_reached?code_reviews_today_count -> guard_rail_checks_today_countcode_reviews_remaining_today -> guard_rail_checks_remaining_todayapp/models/deployment.rb)has_many :code_reviews -> has_many :guard_rail_checkscan_request_code_review? -> can_request_guard_rail_check?latest_code_review -> latest_guard_rail_checkcode_review_count -> guard_rail_check_countremaining_code_reviews -> remaining_guard_rail_checksapp/controllers/deployments/create_controller.rb)code_review? -> guard_rails? (check params[:deployment][:mode] == 'guard_rails')code_review_eligible? -> guard_rails_eligible?handle_ineligible_code_review -> handle_ineligible_guard_railscode_review_project_deployment_path -> guard_rails_project_deployment_pathdeployment_code_review_started -> deployment_guard_rails_startedapp/presenters/deployment_component_presenter.rb)code_reviews -> guard_rail_checks (hash key + method)code_review_enabled? -> guard_rails_enabled?can_request_code_review? -> can_request_guard_rail_check?app/views/deployments/code_review/ -> app/views/deployments/guard_rails/| Old | New |
|---|---|
CodeReviewReport.jsx | GuardRailReport.jsx |
CodeReviewLoader.jsx | GuardRailLoader.jsx |
CodeReviewScore.jsx | GuardRailScore.jsx |
CodeReviewFinding.jsx | GuardRailFinding.jsx |
Update component registration names (DeployHQ.components.CodeReviewReport -> DeployHQ.components.GuardRailReport), user-facing text, and prop names.
In NewDeploymentForm.jsx: change mode value code_review -> guard_rails, button text -> "Run Guard Rails", update descriptions.
| Old | New |
|---|---|
atoms/_code-review-score.scss | atoms/_guard-rail-score.scss |
molecules/_code-review-finding.scss | molecules/_guard-rail-finding.scss |
organisms/_code-review-report.scss | organisms/_guard-rail-report.scss |
organisms/_code-review-loader.scss | organisms/_guard-rail-loader.scss |
Rename all CSS classes: .o-code-review-* -> .o-guard-rail-*, .m-code-review-* -> .m-guard-rail-*, .a-code-review-* -> .a-guard-rail-*
Update SCSS index files that import these partials.
| Old | New |
|---|---|
spec/models/code_review_spec.rb | spec/models/guard_rail_check_spec.rb |
spec/models/code_review_usage_spec.rb | spec/models/guard_rail_check_usage_spec.rb |
spec/jobs/generate_code_review_job_spec.rb | spec/jobs/generate_guard_rail_check_job_spec.rb |
spec/factories/code_review_factory.rb | spec/factories/guard_rail_check_factory.rb |
spec/factories/code_review_usage_factory.rb | spec/factories/guard_rail_check_usage_factory.rb |
Keep spec/services/ai/code_review_service_spec.rb as-is (service name unchanged).
Rename across all tiers:
ai_code_review_allowed -> guard_rails_alloweddaily_code_review_limit -> daily_guard_rail_limit:code_review_requested -> :guard_rail_check_requested:code_review_retried -> :guard_rail_check_retried:code_review_feedback -> :guard_rail_check_feedback:deployment_code_review_started -> :deployment_guard_rails_startedIn GenerateGuardRailCheckJob:
code_review_started -> guard_rail_check_startedcode_review_completed -> guard_rail_check_completedcode_review_failed -> guard_rail_check_failedUpdate corresponding JS WebSocket listeners in GuardRailLoader.jsx.
Update route helpers: code_review_project_deployment_path -> guard_rails_project_deployment_path, etc.
Configurable per-project rules that users trigger manually before deploying.
guard_rail_rulesMigration: db/migrate/TIMESTAMP_create_guard_rail_rules.rb
create_table :guard_rail_rules do |t|
t.string :parent_type, null: false
t.integer :parent_id, null: false
t.string :identifier, null: false
t.string :rule_type, null: false
t.boolean :enabled, default: true, null: false
t.boolean :blocking, default: true, null: false
t.text :configuration # JSON
t.integer :position, default: 0
t.timestamps
end
add_index :guard_rail_rules, :identifier, unique: true, length: 191
add_index :guard_rail_rules, [:parent_type, :parent_id]
add_index :guard_rail_rules, :rule_type, length: 191
Uses polymorphic parent pattern (matches servers, config_files, etc.).
GuardRailRuleFile: app/models/guard_rail_rule.rb
RULE_TYPES = %w[branch_restriction ai_code_review].freeze (start small, expand later)belongs_to :parent, polymorphic: trueserialize :configuration, JSONenabled, blocking, ordered, for_typeIn app/models/project.rb:
has_many :guard_rail_rules, as: :parent, dependent: :destroyFile: app/services/guard_rails/executor.rb
Orchestrates running all enabled rules for a deployment:
File: app/services/guard_rails/checkers/base.rb
Interface: .check(deployment, rule) -> CheckResult with success(), failure(), pending() helpers.
File: app/services/guard_rails/checkers/branch_restriction.rb
Configuration:
{
"mode": "allowlist",
"branches": ["main", "release/*"]
}
Synchronous check using File.fnmatch for glob pattern matching against the deployment's branch.
File: app/services/guard_rails/checkers/ai_code_review.rb
Wraps the existing async AI review flow. Configuration:
{
"block_on_critical": true
}
File: app/controllers/guard_rail_rules_controller.rb
CRUD for managing rules per project. Actions: index, new, create, edit, update, destroy.
Follows the same pattern as excluded_files_controller.rb, config_files_controller.rb:
active_nav :projects, :guard_rails@project.guard_rail_rulesDirectory: app/views/guard_rail_rules/
index.html.haml - list of rule cards with enable/disable toggles (see mockup 2)_form.html.haml - type-specific configuration form (see mockup 3)new.html.haml / edit.html.hamlUses existing UI patterns: o-listing-items, a-button, m-form-footer, shared/help layout.
Add to app/views/layouts/_project_navigation.html.haml:
%li.m-sidebar-menu__item{class: [active_nav_class(:guard_rails)]}
= link_to project_guard_rail_rules_path(@project) do
= icon_tag 'shield'
Guard Rails
resources :projects do
resources :guard_rail_rules, except: [:show]
end
The flow remains opt-in, same as current Code Review:
mode=guard_rails)CreateController creates a preview deploymentDeployments::GuardRailsController#indexGuardRails::Executor for synchronous checks immediatelyThe GuardRailsController#index view is updated to show the multi-check results page instead of just the AI review. When all checks pass/complete, the "Run Deployment" button appears.
Pass guard rail rules data to the React component:
guardRailsEnabled: whether the project has any enabled rulesguardRailRulesCount: number of enabled rulesNot in initial scope, but planned:
guard_rail_approvals table)bin/rails db:migrate succeeds; bin/rails db:rollback worksbin/rspec passes after all renamesrubocop passes on new/changed filesbin/rails routes | grep guard_rail shows correct mappingsapp/models/code_review.rb -> app/models/guard_rail_check.rbapp/models/code_review_usage.rb -> app/models/guard_rail_check_usage.rbapp/controllers/deployments/code_review_controller.rb -> app/controllers/deployments/guard_rails_controller.rbapp/controllers/deployments/create_controller.rbapp/jobs/generate_code_review_job.rb -> app/jobs/generate_guard_rail_check_job.rbapp/models/deployment.rbapp/models/account.rbapp/presenters/deployment_component_presenter.rbapp/views/deployments/code_review/ -> app/views/deployments/guard_rails/app/frontend/components/application/CodeReview*.jsx (4 files)app/frontend/components/application/NewDeploymentForm.jsxapp/assets/stylesheets/application/ (4 SCSS files)config/routes.rbconfig/packages.ymlapp/helpers/deployments_helper.rbapp/assets/javascripts/routes.jsdb/migrate/TIMESTAMP_create_guard_rail_rules.rbapp/models/guard_rail_rule.rbapp/services/guard_rails/executor.rbapp/services/guard_rails/checkers/base.rbapp/services/guard_rails/checkers/branch_restriction.rbapp/services/guard_rails/checkers/ai_code_review.rbapp/controllers/guard_rail_rules_controller.rbapp/views/guard_rail_rules/ (index, new, edit, _form)app/views/layouts/_project_navigation.html.haml (add nav item)
comments (0)