@codyswann/lisa 1.53.0 → 1.53.1

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 (38) hide show
  1. package/all/merge/.claude/settings.json +2 -1
  2. package/package.json +1 -1
  3. package/plugins/lisa-expo/.mcp.json +8 -0
  4. package/plugins/lisa-rails/rules/lisa.md +17 -15
  5. package/plugins/src/expo/.mcp.json +8 -0
  6. package/{rails/copy-overwrite/.claude → plugins/src/rails}/rules/lisa.md +7 -12
  7. package/cdk/copy-overwrite/README.md +0 -81
  8. package/expo/copy-overwrite/.mcp.json +0 -25
  9. package/expo/copy-overwrite/README.md +0 -89
  10. package/nestjs/copy-overwrite/README.md +0 -81
  11. package/rails/copy-overwrite/.claude/rules/rails-conventions.md +0 -176
  12. /package/expo/{copy-overwrite → create-only}/.zap/baseline.conf +0 -0
  13. /package/expo/{copy-overwrite → create-only}/lighthouserc.js +0 -0
  14. /package/expo/{copy-overwrite → create-only}/scripts/zap-baseline.sh +0 -0
  15. /package/nestjs/{copy-overwrite → create-only}/.github/k6/BROWSER_TESTING_NOTE.md +0 -0
  16. /package/nestjs/{copy-overwrite → create-only}/.github/k6/INTEGRATION_GUIDE.md +0 -0
  17. /package/nestjs/{copy-overwrite → create-only}/.github/k6/README.md +0 -0
  18. /package/nestjs/{copy-overwrite → create-only}/.github/k6/SCENARIO_SELECTION_GUIDE.md +0 -0
  19. /package/nestjs/{copy-overwrite → create-only}/.github/k6/examples/customer-deploy-integration.yml +0 -0
  20. /package/nestjs/{copy-overwrite → create-only}/.github/k6/examples/data-driven-test.js +0 -0
  21. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scenarios/load.js +0 -0
  22. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scenarios/load.json +0 -0
  23. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scenarios/smoke.js +0 -0
  24. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scenarios/smoke.json +0 -0
  25. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scenarios/soak.js +0 -0
  26. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scenarios/soak.json +0 -0
  27. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scenarios/spike.js +0 -0
  28. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scenarios/spike.json +0 -0
  29. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scenarios/stress.js +0 -0
  30. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scenarios/stress.json +0 -0
  31. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scripts/api-test.js +0 -0
  32. /package/nestjs/{copy-overwrite → create-only}/.github/k6/scripts/default-test.js +0 -0
  33. /package/nestjs/{copy-overwrite → create-only}/.github/k6/thresholds/normal.json +0 -0
  34. /package/nestjs/{copy-overwrite → create-only}/.github/k6/thresholds/relaxed.json +0 -0
  35. /package/nestjs/{copy-overwrite → create-only}/.github/k6/thresholds/strict.json +0 -0
  36. /package/nestjs/{copy-overwrite → create-only}/.zap/baseline.conf +0 -0
  37. /package/nestjs/{copy-overwrite → create-only}/scripts/zap-baseline.sh +0 -0
  38. /package/rails/{copy-overwrite → merge}/.claude/settings.json +0 -0
@@ -19,7 +19,8 @@
19
19
  "BASH_DEFAULT_TIMEOUT_MS": "1800000",
20
20
  "BASH_MAX_TIMEOUT_MS": "7200000",
21
21
  "CLAUDE_DEBUG": "0",
22
- "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
22
+ "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1",
23
+ "ENABLE_LSP_TOOL": "1"
23
24
  },
24
25
  "permissions": {
25
26
  "deny": ["Read(./.entire/metadata/**)"]
package/package.json CHANGED
@@ -72,7 +72,7 @@
72
72
  "axios": ">=1.13.5"
73
73
  },
74
74
  "name": "@codyswann/lisa",
75
- "version": "1.53.0",
75
+ "version": "1.53.1",
76
76
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
77
77
  "main": "dist/index.js",
78
78
  "exports": {
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "expo-docs": {
4
+ "command": "npx",
5
+ "args": ["expo-local-docs-mcp"]
6
+ }
7
+ }
8
+ }
@@ -6,15 +6,22 @@ The following files are managed by Lisa and will be overwritten on every `lisa`
6
6
 
7
7
  | Managed File (do not edit) | Local Override (edit this instead) |
8
8
  |---|---|
9
- | `eslint.config.ts` | `eslint.config.local.ts` |
10
- | `jest.config.ts` | `jest.config.local.ts` |
11
- | `tsconfig.json` | `tsconfig.local.json` |
9
+ | `.rubocop.yml` | `.rubocop.local.yml` |
12
10
 
13
11
  ## Create-only files (edit freely, Lisa won't overwrite)
14
12
 
15
13
  - `.claude/rules/PROJECT_RULES.md`
16
- - `eslint.thresholds.json`
17
- - `jest.thresholds.json`
14
+ - `.rubocop.local.yml`
15
+ - `.simplecov`
16
+ - `.reek.yml`
17
+ - `.rspec`
18
+ - `sonar-project.properties`
19
+ - `spec/spec_helper.rb`
20
+ - `spec/rails_helper.rb`
21
+ - `.github/workflows/quality.yml`
22
+ - `.github/workflows/ci.yml`
23
+ - `.github/workflows/release.yml`
24
+ - `VERSION`
18
25
 
19
26
  ## Deep-merged by Lisa (Lisa wins conflicts, but project can add its own keys)
20
27
 
@@ -22,16 +29,11 @@ The following files are managed by Lisa and will be overwritten on every `lisa`
22
29
 
23
30
  ## Plugin-managed content (agents, skills, hooks, commands, rules)
24
31
 
25
- These resources are distributed via the stack Claude Code plugin (e.g., `typescript@lisa`). Rules — including this file — are injected into each prompt automatically. Do not add these files to your project directory.
32
+ These resources are distributed via the stack Claude Code plugin (`rails@lisa`). Rules — including this file — are injected into each prompt automatically. Do not add these files to your project directory.
26
33
 
27
34
  ## Copy-overwrite files (do not edit — full list)
28
35
 
29
- - `.prettierrc.json`, `.prettierignore`, `.lintstagedrc.json`, `.versionrc`, `.nvmrc`
30
- - `.yamllint`, `.gitleaksignore`, `.coderabbit.yml`, `commitlint.config.cjs`, `sgconfig.yml`, `knip.json`
31
- - `.safety-net.json`, `audit.ignore.config.json`
32
- - `eslint.base.ts`, `eslint.typescript.ts` (+ `expo`/`nestjs`/`cdk` variants), `eslint.slow.config.ts`
33
- - `jest.base.ts`, `jest.typescript.ts` (+ variants)
34
- - `tsconfig.base.json`, `tsconfig.typescript.json` (+ variants), `tsconfig.eslint.json`, `tsconfig.build.json`, `tsconfig.spec.json`
35
- - `.github/workflows/quality.yml`, `release.yml`, `claude.yml`, and all other Claude/CI workflows
36
- - `.github/dependabot.yml`, `.github/GITHUB_ACTIONS.md`
37
- - `ast-grep/rules/`, `ast-grep/utils/`, `ast-grep/rule-tests/`
36
+ - `.safety-net.json`
37
+ - `.rubocop.yml`, `.versionrc`, `lefthook.yml`, `Gemfile.lisa`
38
+ - `config/initializers/version.rb`
39
+ - `.coderabbit.yml`, `commitlint.config.cjs`
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "expo-docs": {
4
+ "command": "npx",
5
+ "args": ["expo-local-docs-mcp"]
6
+ }
7
+ }
8
+ }
@@ -23,22 +23,17 @@ The following files are managed by Lisa and will be overwritten on every `lisa`
23
23
  - `.github/workflows/release.yml`
24
24
  - `VERSION`
25
25
 
26
- ## Directories with both Lisa-managed and project content
26
+ ## Deep-merged by Lisa (Lisa wins conflicts, but project can add its own keys)
27
27
 
28
- These directories contain files deployed by Lisa **and** files you create. Do not edit or delete Lisa-managed files — they will be overwritten. You **can** freely add your own. Check `.lisa-manifest` to see which specific files Lisa manages.
28
+ - `.claude/settings.json`
29
+
30
+ ## Plugin-managed content (agents, skills, hooks, commands, rules)
29
31
 
30
- - `.claude/skills/`Add your own skill directories alongside Lisa's
31
- - `.claude/commands/` — Add your own command namespaces alongside Lisa's
32
- - `.claude/hooks/` — Add your own hook scripts alongside Lisa's
33
- - `.claude/agents/` — Add your own agent files alongside Lisa's
32
+ These resources are distributed via the stack Claude Code plugin (`rails@lisa`). Rules including this file are injected into each prompt automatically. Do not add these files to your project directory.
34
33
 
35
- ## Files and directories with NO local override (do not edit at all)
34
+ ## Copy-overwrite files (do not edit full list)
36
35
 
37
- - `.claude/rules/coding-philosophy.md`, `.claude/rules/plan.md`, `.claude/rules/verfication.md`
38
- - `.claude/rules/rails-conventions.md`
39
- - `CLAUDE.md`, `HUMAN.md`, `.safety-net.json`
36
+ - `.safety-net.json`
40
37
  - `.rubocop.yml`, `.versionrc`, `lefthook.yml`, `Gemfile.lisa`
41
38
  - `config/initializers/version.rb`
42
39
  - `.coderabbit.yml`, `commitlint.config.cjs`
43
- - `.claude/settings.json`
44
- - `.claude/README.md`, `.claude/REFERENCE.md`
@@ -1,81 +0,0 @@
1
- # CDK
2
-
3
- Developers write specs and answer questions. Agents implement, test, verify, question, and document.
4
-
5
- ## About This Project
6
-
7
- > Ask Claude: "What is the purpose of this project and how does it work?"
8
-
9
- ## Step 1: Install Claude Code
10
-
11
- ```bash
12
- brew install claude-code
13
- # Or: npm install -g @anthropic-ai/claude-code
14
- ```
15
-
16
- ## Step 2: Set Up This Project
17
-
18
- > Ask Claude: "I just cloned this repo. Walk me through the full setup including installing dependencies, environment variables, and any other configuration."
19
-
20
- ## Step 3: Verify the Infrastructure
21
-
22
- > Ask Claude: "How do I synthesize the CDK stacks and verify the templates are valid?"
23
-
24
- ## Step 4: Work on a Feature
25
-
26
- > Ask Claude: "I have Jira ticket [TICKET-ID]. Research the codebase, create a plan, and implement it."
27
-
28
- Or use utility commands:
29
-
30
- - `/plan:add-test-coverage` - Increase test coverage to a threshold
31
- - `/plan:fix-linter-error` - Fix ESLint rule violations
32
- - `/plan:local-code-review` - Review local branch changes
33
- - `/plan:lower-code-complexity` - Reduce cognitive complexity
34
- - `/plan:reduce-max-lines` - Reduce max file lines threshold
35
- - `/plan:reduce-max-lines-per-function` - Reduce max function lines
36
-
37
- ## Lisa Commands
38
-
39
- > Ask Claude: "What Lisa commands are available and how do I use them? Read HUMAN.md and give me a summary."
40
-
41
- ## Common Tasks
42
-
43
- ### Code Review
44
-
45
- > Ask Claude: "Review the changes on this branch and suggest improvements."
46
-
47
- ### Submit a PR
48
-
49
- > Ask Claude: "Commit my changes and open a pull request."
50
-
51
- ### Fix Lint Errors
52
-
53
- > Ask Claude: "Run the linter and fix all errors."
54
-
55
- ### Add Test Coverage
56
-
57
- > Ask Claude: "Increase test coverage for the files I changed."
58
-
59
- ### Synthesize CloudFormation Templates
60
-
61
- > Ask Claude: "Run CDK synth and verify the CloudFormation templates are generated correctly."
62
-
63
- ### Diff Against Deployed Stacks
64
-
65
- > Ask Claude: "Run CDK diff to show what changes would be deployed compared to the current stacks."
66
-
67
- ### Deploy
68
-
69
- > Ask Claude: "Walk me through deploying this project."
70
-
71
- ## Project Standards
72
-
73
- > Ask Claude: "What coding standards and conventions does this project follow?"
74
-
75
- ## Architecture
76
-
77
- > Ask Claude: "Explain the architecture of this project, including key components and how they interact."
78
-
79
- ## Troubleshooting
80
-
81
- > Ask Claude: "I'm having an issue with [describe problem]. Help me debug it."
@@ -1,25 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "expo-docs": {
4
- "command": "npx",
5
- "args": ["expo-local-docs-mcp"]
6
- },
7
- "sonarqube": {
8
- "command": "docker",
9
- "args": [
10
- "run",
11
- "-i",
12
- "--rm",
13
- "-e",
14
- "SONARQUBE_TOKEN",
15
- "-e",
16
- "SONARQUBE_ORG",
17
- "mcp/sonarqube"
18
- ],
19
- "env": {
20
- "SONARQUBE_TOKEN": "${SONAR_TOKEN}",
21
- "SONARQUBE_ORG": "${SONAR_ORG}"
22
- }
23
- }
24
- }
25
- }
@@ -1,89 +0,0 @@
1
- # Expo
2
-
3
- Developers write specs and answer questions. Agents implement, test, verify, question, and document.
4
-
5
- ## About This Project
6
-
7
- > Ask Claude: "What is the purpose of this project and how does it work?"
8
-
9
- ## Step 1: Install Claude Code
10
-
11
- ```bash
12
- brew install claude-code
13
- # Or: npm install -g @anthropic-ai/claude-code
14
- ```
15
-
16
- ## Step 2: Set Up This Project
17
-
18
- > Ask Claude: "I just cloned this repo. Walk me through the full setup including installing dependencies, environment variables, and any other configuration."
19
-
20
- ## Step 3: Run the App Locally
21
-
22
- > Ask Claude: "How do I start the app locally? Walk me through the steps and verify it's running."
23
-
24
- ## Step 4: Work on a Feature
25
-
26
- > Ask Claude: "I have Jira ticket [TICKET-ID]. Research the codebase, create a plan, and implement it."
27
-
28
- Or use utility commands:
29
-
30
- - `/plan:add-test-coverage` - Increase test coverage to a threshold
31
- - `/plan:fix-linter-error` - Fix ESLint rule violations
32
- - `/plan:local-code-review` - Review local branch changes
33
- - `/plan:lower-code-complexity` - Reduce cognitive complexity
34
- - `/plan:reduce-max-lines` - Reduce max file lines threshold
35
- - `/plan:reduce-max-lines-per-function` - Reduce max function lines
36
-
37
- ## Lisa Commands
38
-
39
- > Ask Claude: "What Lisa commands are available and how do I use them? Read HUMAN.md and give me a summary."
40
-
41
- ## Common Tasks
42
-
43
- ### Code Review
44
-
45
- > Ask Claude: "Review the changes on this branch and suggest improvements."
46
-
47
- ### Submit a PR
48
-
49
- > Ask Claude: "Commit my changes and open a pull request."
50
-
51
- ### Fix Lint Errors
52
-
53
- > Ask Claude: "Run the linter and fix all errors."
54
-
55
- ### Add Test Coverage
56
-
57
- > Ask Claude: "Increase test coverage for the files I changed."
58
-
59
- ### Run on iOS
60
-
61
- > Ask Claude: "Start the app on the iOS simulator and verify it launches correctly."
62
-
63
- ### Run on Android
64
-
65
- > Ask Claude: "Start the app on the Android emulator and verify it launches correctly."
66
-
67
- ### Run on Web
68
-
69
- > Ask Claude: "Start the app in a web browser and verify it loads correctly."
70
-
71
- ### Generate Types After Schema Changes
72
-
73
- > Ask Claude: "The API schema has changed. Regenerate types and fix any resulting type errors."
74
-
75
- ### Deploy
76
-
77
- > Ask Claude: "Walk me through deploying this project."
78
-
79
- ## Project Standards
80
-
81
- > Ask Claude: "What coding standards and conventions does this project follow?"
82
-
83
- ## Architecture
84
-
85
- > Ask Claude: "Explain the architecture of this project, including key components and how they interact."
86
-
87
- ## Troubleshooting
88
-
89
- > Ask Claude: "I'm having an issue with [describe problem]. Help me debug it."
@@ -1,81 +0,0 @@
1
- # NestJS
2
-
3
- Developers write specs and answer questions. Agents implement, test, verify, question, and document.
4
-
5
- ## About This Project
6
-
7
- > Ask Claude: "What is the purpose of this project and how does it work?"
8
-
9
- ## Step 1: Install Claude Code
10
-
11
- ```bash
12
- brew install claude-code
13
- # Or: npm install -g @anthropic-ai/claude-code
14
- ```
15
-
16
- ## Step 2: Set Up This Project
17
-
18
- > Ask Claude: "I just cloned this repo. Walk me through the full setup including installing dependencies, environment variables, and any other configuration."
19
-
20
- ## Step 3: Run the App Locally
21
-
22
- > Ask Claude: "How do I start the app locally? Walk me through the steps and verify it's running."
23
-
24
- ## Step 4: Work on a Feature
25
-
26
- > Ask Claude: "I have Jira ticket [TICKET-ID]. Research the codebase, create a plan, and implement it."
27
-
28
- Or use utility commands:
29
-
30
- - `/plan:add-test-coverage` - Increase test coverage to a threshold
31
- - `/plan:fix-linter-error` - Fix ESLint rule violations
32
- - `/plan:local-code-review` - Review local branch changes
33
- - `/plan:lower-code-complexity` - Reduce cognitive complexity
34
- - `/plan:reduce-max-lines` - Reduce max file lines threshold
35
- - `/plan:reduce-max-lines-per-function` - Reduce max function lines
36
-
37
- ## Lisa Commands
38
-
39
- > Ask Claude: "What Lisa commands are available and how do I use them? Read HUMAN.md and give me a summary."
40
-
41
- ## Common Tasks
42
-
43
- ### Code Review
44
-
45
- > Ask Claude: "Review the changes on this branch and suggest improvements."
46
-
47
- ### Submit a PR
48
-
49
- > Ask Claude: "Commit my changes and open a pull request."
50
-
51
- ### Fix Lint Errors
52
-
53
- > Ask Claude: "Run the linter and fix all errors."
54
-
55
- ### Add Test Coverage
56
-
57
- > Ask Claude: "Increase test coverage for the files I changed."
58
-
59
- ### Run Database Migrations
60
-
61
- > Ask Claude: "Run pending database migrations and verify the schema is up to date."
62
-
63
- ### Test API Endpoints
64
-
65
- > Ask Claude: "How do I test the API endpoints locally?"
66
-
67
- ### Deploy
68
-
69
- > Ask Claude: "Walk me through deploying this project."
70
-
71
- ## Project Standards
72
-
73
- > Ask Claude: "What coding standards and conventions does this project follow?"
74
-
75
- ## Architecture
76
-
77
- > Ask Claude: "Explain the architecture of this project, including key components and how they interact."
78
-
79
- ## Troubleshooting
80
-
81
- > Ask Claude: "I'm having an issue with [describe problem]. Help me debug it."
@@ -1,176 +0,0 @@
1
- # Rails Coding Conventions
2
-
3
- This rule enforces Rails-specific coding standards for consistency, maintainability, and performance.
4
-
5
- ## Fat Models, Skinny Controllers
6
-
7
- Controllers handle HTTP concerns only. Business logic belongs in models or service objects.
8
-
9
- ```ruby
10
- # Correct — controller delegates to model
11
- class OrdersController < ApplicationController
12
- def create
13
- @order = Order.place(order_params, current_user)
14
- redirect_to @order
15
- end
16
- end
17
-
18
- # Wrong — business logic in controller
19
- class OrdersController < ApplicationController
20
- def create
21
- @order = Order.new(order_params)
22
- @order.user = current_user
23
- @order.total = @order.line_items.sum(&:price)
24
- @order.apply_discount(current_user.discount_rate)
25
- @order.save!
26
- OrderMailer.confirmation(@order).deliver_later
27
- redirect_to @order
28
- end
29
- end
30
- ```
31
-
32
- ## Service Objects
33
-
34
- Extract complex business logic into service objects when a model method would be too large or spans multiple models.
35
-
36
- ```ruby
37
- # app/services/order_placement_service.rb
38
- class OrderPlacementService
39
- def initialize(user:, params:)
40
- @user = user
41
- @params = params
42
- end
43
-
44
- def call
45
- order = Order.new(@params)
46
- order.user = @user
47
- order.calculate_total
48
- order.save!
49
- OrderMailer.confirmation(order).deliver_later
50
- order
51
- end
52
- end
53
- ```
54
-
55
- ## Concerns
56
-
57
- Use concerns to share behavior across models or controllers. Keep concerns focused on a single responsibility.
58
-
59
- ```ruby
60
- # app/models/concerns/searchable.rb
61
- module Searchable
62
- extend ActiveSupport::Concern
63
-
64
- included do
65
- scope :search, ->(query) { where("name ILIKE ?", "%#{query}%") }
66
- end
67
- end
68
- ```
69
-
70
- ## ActiveRecord Patterns
71
-
72
- ### Scopes over class methods for chainable queries
73
-
74
- ```ruby
75
- # Correct — scope
76
- scope :active, -> { where(active: true) }
77
- scope :recent, -> { order(created_at: :desc) }
78
-
79
- # Wrong — class method for simple query
80
- def self.active
81
- where(active: true)
82
- end
83
- ```
84
-
85
- ### Validations
86
-
87
- ```ruby
88
- # Use built-in validators
89
- validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
90
- validates :age, numericality: { greater_than: 0 }
91
- ```
92
-
93
- ### Callbacks — use sparingly
94
-
95
- Prefer explicit service objects over callbacks for complex side effects. Callbacks are acceptable for simple data normalization.
96
-
97
- ```ruby
98
- # Acceptable — simple normalization
99
- before_validation :normalize_email
100
-
101
- private
102
-
103
- def normalize_email
104
- self.email = email&.downcase&.strip
105
- end
106
- ```
107
-
108
- ## N+1 Query Prevention
109
-
110
- Always use `includes`, `preload`, or `eager_load` to prevent N+1 queries. The Bullet gem is included to detect these in development.
111
-
112
- ```ruby
113
- # Correct — eager loading
114
- @posts = Post.includes(:author, :comments).where(published: true)
115
-
116
- # Wrong — N+1 query
117
- @posts = Post.where(published: true)
118
- @posts.each { |post| post.author.name } # N+1!
119
- ```
120
-
121
- ## Strong Parameters
122
-
123
- Always use strong parameters in controllers. Never use `permit!`.
124
-
125
- ```ruby
126
- # Correct
127
- def order_params
128
- params.require(:order).permit(:product_id, :quantity, :notes)
129
- end
130
-
131
- # Wrong — permits everything
132
- def order_params
133
- params.require(:order).permit!
134
- end
135
- ```
136
-
137
- ## Database Migrations
138
-
139
- - Use `strong_migrations` gem constraints (included via Gemfile.lisa)
140
- - Never modify `db/schema.rb` directly
141
- - Always add indexes for foreign keys and commonly queried columns
142
- - Use `change` method when the migration is reversible; use `up`/`down` when it is not
143
-
144
- ```ruby
145
- class AddIndexToOrdersUserId < ActiveRecord::Migration[7.2]
146
- def change
147
- add_index :orders, :user_id
148
- end
149
- end
150
- ```
151
-
152
- ## Testing with RSpec
153
-
154
- - Use `let` and `let!` for test setup
155
- - Use `described_class` instead of repeating the class name
156
- - Use `factory_bot` for test data, not fixtures
157
- - Use `shoulda-matchers` for model validation tests
158
- - Keep tests focused — one assertion concept per example
159
-
160
- ```ruby
161
- RSpec.describe Order, type: :model do
162
- describe "validations" do
163
- it { is_expected.to validate_presence_of(:user) }
164
- it { is_expected.to validate_numericality_of(:total).is_greater_than(0) }
165
- end
166
-
167
- describe ".recent" do
168
- it "returns orders in descending creation order" do
169
- old_order = create(:order, created_at: 1.day.ago)
170
- new_order = create(:order, created_at: 1.hour.ago)
171
-
172
- expect(described_class.recent).to eq([new_order, old_order])
173
- end
174
- end
175
- end
176
- ```