tsykvas_rails_template 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 (79) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +200 -0
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +589 -0
  6. data/Rakefile +17 -0
  7. data/lib/generators/tsykvas_rails_template/companions/companions_generator.rb +273 -0
  8. data/lib/generators/tsykvas_rails_template/concept/concept_generator.rb +145 -0
  9. data/lib/generators/tsykvas_rails_template/concept/templates/component/edit.html.slim.tt +5 -0
  10. data/lib/generators/tsykvas_rails_template/concept/templates/component/edit.rb.tt +11 -0
  11. data/lib/generators/tsykvas_rails_template/concept/templates/component/index.html.slim.tt +5 -0
  12. data/lib/generators/tsykvas_rails_template/concept/templates/component/index.rb.tt +11 -0
  13. data/lib/generators/tsykvas_rails_template/concept/templates/component/new.html.slim.tt +5 -0
  14. data/lib/generators/tsykvas_rails_template/concept/templates/component/new.rb.tt +11 -0
  15. data/lib/generators/tsykvas_rails_template/concept/templates/component/show.html.slim.tt +4 -0
  16. data/lib/generators/tsykvas_rails_template/concept/templates/component/show.rb.tt +11 -0
  17. data/lib/generators/tsykvas_rails_template/concept/templates/controller.rb.tt +45 -0
  18. data/lib/generators/tsykvas_rails_template/concept/templates/operation/create.rb.tt +31 -0
  19. data/lib/generators/tsykvas_rails_template/concept/templates/operation/destroy.rb.tt +13 -0
  20. data/lib/generators/tsykvas_rails_template/concept/templates/operation/edit.rb.tt +10 -0
  21. data/lib/generators/tsykvas_rails_template/concept/templates/operation/index.rb.tt +9 -0
  22. data/lib/generators/tsykvas_rails_template/concept/templates/operation/new.rb.tt +10 -0
  23. data/lib/generators/tsykvas_rails_template/concept/templates/operation/show.rb.tt +10 -0
  24. data/lib/generators/tsykvas_rails_template/concept/templates/operation/update.rb.tt +31 -0
  25. data/lib/generators/tsykvas_rails_template/install/bootstrap_installer.rb +225 -0
  26. data/lib/generators/tsykvas_rails_template/install/install_generator.rb +298 -0
  27. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/buddy.md +157 -0
  28. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/code-reviewer.md +117 -0
  29. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/security-reviewer.md +113 -0
  30. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/tech-lead.md +150 -0
  31. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/check.md +51 -0
  32. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/code-review.md +60 -0
  33. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/docs-create.md +102 -0
  34. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/pr-review.md +81 -0
  35. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/pushit.md +160 -0
  36. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/refactor.md +132 -0
  37. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/task-sum.md +47 -0
  38. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/tests.md +67 -0
  39. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/tsykvas-claude.md +262 -0
  40. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-docs.md +78 -0
  41. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-rules.md +102 -0
  42. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-tests.md +135 -0
  43. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/architecture.md +315 -0
  44. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/authentication.md +96 -0
  45. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/background-jobs.md +135 -0
  46. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/code-style.md +101 -0
  47. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/commands.md +34 -0
  48. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/companions.md +128 -0
  49. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/concepts-refactoring.md +194 -0
  50. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/database.md +135 -0
  51. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/deployment.md +138 -0
  52. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/design-system.md +322 -0
  53. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/documentation.md +89 -0
  54. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/forms.md +174 -0
  55. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/i18n.md +165 -0
  56. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/routing-and-namespaces.md +114 -0
  57. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/security.md +122 -0
  58. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/stimulus-controllers.md +166 -0
  59. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/testing-examples.md +180 -0
  60. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/testing.md +117 -0
  61. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/tsykvas_rails_template.md +280 -0
  62. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/ui-components.md +196 -0
  63. data/lib/generators/tsykvas_rails_template/install/templates/CLAUDE.md.tt +81 -0
  64. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/component/base.rb +6 -0
  65. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/operation/base.rb +124 -0
  66. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/operation/result.rb +56 -0
  67. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/component/index.html.slim +49 -0
  68. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/component/index.rb +11 -0
  69. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/operation/index.rb +17 -0
  70. data/lib/generators/tsykvas_rails_template/install/templates/app/controllers/concerns/operations_methods.rb +148 -0
  71. data/lib/generators/tsykvas_rails_template/install/templates/app/controllers/home_controller.rb +10 -0
  72. data/lib/generators/tsykvas_rails_template/install/templates/app/policies/application_policy.rb +33 -0
  73. data/lib/generators/tsykvas_rails_template/install/templates/app/policies/home_policy.rb +8 -0
  74. data/lib/tasks/tsykvas.rake +11 -0
  75. data/lib/tsykvas_rails_template/probe.rb +236 -0
  76. data/lib/tsykvas_rails_template/railtie.rb +13 -0
  77. data/lib/tsykvas_rails_template/version.rb +5 -0
  78. data/lib/tsykvas_rails_template.rb +18 -0
  79. metadata +183 -0
@@ -0,0 +1,262 @@
1
+ # /tsykvas-claude
2
+
3
+ Bootstrap and tailor `CLAUDE.md` + `.claude/docs/` to **this** project.
4
+
5
+ If `CLAUDE.md` doesn't exist yet, run `claude init` first to seed Claude's
6
+ own opinionated overview of the host. Then run `bundle exec rake tsykvas:probe`
7
+ for a deterministic inventory, integrate the gem's fenced sections into
8
+ `CLAUDE.md` (preserving anything Claude wrote outside the fences), and
9
+ **generate** host-specific docs (architecture, code-style, commands, testing,
10
+ ui-components, etc.) from the gem's reference templates.
11
+
12
+ Supports `--dry-run` to print a unified diff without writing.
13
+
14
+ ---
15
+
16
+ ## Phase 0a — Bootstrap CLAUDE.md if missing
17
+
18
+ Check whether `CLAUDE.md` exists at the repo root:
19
+
20
+ ```bash
21
+ test -f CLAUDE.md && echo "exists" || echo "missing"
22
+ ```
23
+
24
+ - **Exists** → continue to Phase 0b.
25
+ - **Missing** → run `claude init` (the built-in Claude Code command, NOT a
26
+ shell command — invoke it the same way the user would). It produces a
27
+ baseline `CLAUDE.md` with project overview / commands / architecture
28
+ inferred from the codebase. Wait for it to complete, then continue.
29
+
30
+ Why first: every subsequent phase assumes `CLAUDE.md` exists. The gem's
31
+ fence-based rewrite preserves user-authored content outside the fences;
32
+ running `claude init` first gives us a richer baseline (project name,
33
+ commands, conventions Claude inferred) for later phases to wrap fences
34
+ around — instead of starting from a blank shell.
35
+
36
+ If the user invoked `/tsykvas-claude` immediately after `bin/rails g
37
+ tsykvas_rails_template:install` (which creates a CLAUDE.md from the gem's
38
+ template), `claude init` is skipped — the file already exists.
39
+
40
+ ## Phase 0b — Inventory the host project (deterministic)
41
+
42
+ Always run the Ruby probe first:
43
+
44
+ ```bash
45
+ bundle exec rake tsykvas:probe
46
+ ```
47
+
48
+ Output (schema v=2):
49
+
50
+ ```json
51
+ {
52
+ "schema_version": 2,
53
+ "ruby_version": "3.4.7",
54
+ "rails_version": "8.0.2",
55
+ "default_branch": "main",
56
+ "api_only": false,
57
+ "engine_host": false,
58
+ "template_engine": "slim",
59
+ "auth": { "method": "devise", "devise": true, ... },
60
+ "authorization": "pundit",
61
+ "has_api_v1": false,
62
+ "has_bootstrap": false,
63
+ "test_framework": "rspec",
64
+ "background_jobs": ["solid_queue"],
65
+ "databases": ["primary"],
66
+ "concept_folders": ["home", "crm"],
67
+ "application_controller_includes": ["Pundit::Authorization", "OperationsMethods"]
68
+ }
69
+ ```
70
+
71
+ Bind this Hash to `probe`. If `probe.api_only` is true, skip every
72
+ HTML-rendering doc. If `probe.engine_host` is true, treat the host as
73
+ a Rails Engine (skip Application-only instructions).
74
+
75
+ If the probe rake task is missing, the host hasn't run
76
+ `rails g tsykvas_rails_template:install`. Stop and tell the user.
77
+
78
+ (After Phase 0a + 0b are done, treat what follows as starting from "Phase 1".)
79
+
80
+ If the host project has its own `README.md`, read it once for "what is this
81
+ app" copy that should seed the project-overview section.
82
+
83
+ ## Phase 1 — Read existing state
84
+
85
+ For `CLAUDE.md`:
86
+
87
+ - If it doesn't exist → fresh-install case; you'll write it from
88
+ `.claude/docs/tsykvas_rails_template.md` cross-doc index plus the
89
+ fenced-section template.
90
+ - If it exists with `<!-- tsykvas-template:start v=X section=NAME -->` /
91
+ `<!-- tsykvas-template:end -->` markers → you'll **only rewrite content
92
+ inside those markers**. User-authored content above, between, or below
93
+ the fences is sacred.
94
+ - If it exists **without** any fences (the user ran `claude init` before
95
+ the gem's install, then ran `:install` which now leaves CLAUDE.md
96
+ alone) → you'll **add** the gem's fenced sections to a sensible position
97
+ (after user's existing content, separated by a horizontal rule).
98
+ Don't touch user prose.
99
+
100
+ For `.claude/docs/`:
101
+
102
+ - All 20 docs ship at install (under `.claude/docs/<name>.md`).
103
+ - The 3 gem-canonical (`tsykvas_rails_template.md`, `forms.md`,
104
+ `companions.md`) are kept **verbatim**.
105
+ - The other 17 may be **refreshed** in fenced sections to reflect the
106
+ host's actual stack (concept folder names, gem versions, default
107
+ branch, locale config). The reference content is project-agnostic
108
+ and ships scrubbed of any specific domain — refreshing is purely
109
+ about swapping in real values where the templates use placeholders.
110
+
111
+ ## Phase 2a — Plan CLAUDE.md fence integration
112
+
113
+ Target sections (each its own fence in `CLAUDE.md`):
114
+
115
+ | Fence section | What goes inside |
116
+ |---|---|
117
+ | `project-overview` | 5–8 bullets pulled from `probe.ruby_version`, `probe.rails_version`, `probe.template_engine`, `probe.auth`, `probe.background_jobs`, `probe.test_framework`, `probe.default_branch`, `probe.databases`. |
118
+ | `architecture` | One paragraph; do not mention gems the host doesn't have (e.g. don't claim Bootstrap if `probe.has_bootstrap` is false). |
119
+ | `must-know-rules` | Pull from `code-style.md` (after Phase 2b generates it) and **always preserve** the `<Concept>::Form` rule with a link to `.claude/docs/forms.md`. |
120
+ | `routing` | Drop rows whose target doc was not generated (e.g. `api-endpoints.md` if `probe.has_api_v1` is false; `modal-refactoring.md` if `probe.has_bootstrap` is false). |
121
+ | `slash-commands`, `subagents` | Verbatim from the gem template unless host has added/removed files in `.claude/{commands,agents}/`. |
122
+ | `communication` | Verbatim default unless user has a stated preference. |
123
+
124
+ **Budget: `CLAUDE.md` must end up ≤ 100 lines.** Plan within that budget
125
+ before writing anything. Roughly: project-overview ≤ 8 lines, architecture
126
+ ≤ 8 lines, must-know-rules ≤ 12 lines, routing table 4–10 rows, slash-
127
+ commands + subagents tables compact, communication ≤ 4 lines. If a section
128
+ needs more, push the overflow into a new `.claude/docs/<topic>.md` and
129
+ link it from the routing table. Phase 5 will reject the rewrite if
130
+ `wc -l CLAUDE.md` > 100.
131
+
132
+ ## Phase 2b — Plan `.claude/docs/` refresh
133
+
134
+ All 20 docs already ship at install under `.claude/docs/`. Your job here
135
+ is **light refresh**: swap in probe-driven values where the shipped
136
+ template uses placeholders. **Do not trim, summarise, or rewrite the
137
+ shipped content.** The depth is intentional — that's why it ships.
138
+
139
+ | Doc | Refresh strategy |
140
+ |---|---|
141
+ | `architecture.md` | Replace example concept names (`Crm::Property`, `Admin::User`) with the host's actual top-level `concept_folders` if different. |
142
+ | `concepts-refactoring.md` | Keep verbatim — pure architecture walkthrough. |
143
+ | `routing-and-namespaces.md` | Replace example concept names with host's real ones. Keep the example route patterns. |
144
+ | `code-style.md` | Verify references to `.rubocop.yml`, `lefthook.yml`, `.github/workflows/*` resolve to files that actually exist; otherwise mark them with a TODO note. |
145
+ | `commands.md` | If `Procfile.dev` exists, point to `bin/dev`. Otherwise note that the watcher must be run separately. Verify test/lint commands match `bin/`. |
146
+ | `testing.md` + `testing-examples.md` | Confirm `probe.test_framework` (rspec / minitest). Replace any framework-specific snippets accordingly. |
147
+ | `ui-components.md` | Verbatim — Bootstrap is the gem default. |
148
+ | `stimulus-controllers.md` | Verbatim if `app/javascript/controllers/` exists; otherwise add a note that Stimulus is not currently wired. |
149
+ | `forms.md` | **Keep verbatim** (gem-canonical). |
150
+ | `companions.md` | **Keep verbatim** (gem-canonical). |
151
+ | `tsykvas_rails_template.md` | **Keep verbatim** (gem-canonical). |
152
+ | `authentication.md` | Confirm `probe.auth.method`. If `:devise`, leave as is. If custom/warden/jwt/basic_auth, replace the Devise-specific section with the host's actual auth source. |
153
+ | `design-system.md` | Verbatim — generic Bootstrap-default starting point. Host customises to taste. |
154
+ | `i18n.md` | Replace the example default-locale references with the host's actual default locale (read from `config/application.rb`). |
155
+ | `database.md` | Reflect actual `config/database.yml` adapters (postgres / sqlite / mysql / multi-DB). Replace the `<app_name>` placeholder with the actual host app name. |
156
+ | `background-jobs.md` | Confirm `probe.background_jobs`. If SolidQueue, leave as is. If Sidekiq / GoodJob / etc., replace the queue-class references. |
157
+ | `security.md` | Reflect host's actual Brakeman / bundler-audit / CSP setup. |
158
+ | `deployment.md` | If `config/deploy.yml` exists, replace `<your-app>` placeholders with host app name + image. If only `Dockerfile`, mark Kamal sections as optional. |
159
+ | `documentation.md` | Verbatim — generic standards doc. |
160
+
161
+ For each doc you refresh:
162
+
163
+ 1. Read `.claude/docs/<name>.md` from the host.
164
+ 2. Identify placeholder patterns (`<your-app>`, `<app_name>`, `Crm::Property`, `Admin::User`) and probe-driven hooks.
165
+ 3. Substitute real values. Do **not** summarise or trim sample code; the
166
+ shipped depth is intentional and project-agnostic, so it stays.
167
+ 4. Write back to `.claude/docs/<name>.md`.
168
+
169
+ For each doc that's already correct (no placeholders to substitute):
170
+ mark `keep-verbatim` in the change log.
171
+
172
+ ## Phase 3 — Show the plan and wait for confirmation
173
+
174
+ If `--dry-run`:
175
+
176
+ 1. Build the new content for every fence section + every doc to generate
177
+ in memory.
178
+ 2. Print a unified diff (`diff -u` style) for every file that would change.
179
+ 3. Exit. Do not write.
180
+
181
+ Otherwise present a compact plan table with **four action types**:
182
+
183
+ | File | Action | Reason |
184
+ |---|---|---|
185
+ | `CLAUDE.md` (`project-overview` fence) | rewrite-fence | seed from probe |
186
+ | `CLAUDE.md` (no fences yet) | create-fence | install left it untouched; integrate gem sections |
187
+ | `.claude/docs/architecture.md` | refresh | swap example concept names for host's actual `concept_folders` |
188
+ | `.claude/docs/deployment.md` | refresh | replace `<your-app>` with host service name |
189
+ | `.claude/docs/forms.md` | keep-verbatim | gem-canonical |
190
+ | … | … | … |
191
+
192
+ Ask:
193
+
194
+ > Proceed with N changes? (yes / no / dry-run / diff <file>)
195
+
196
+ - `yes` → apply.
197
+ - `no` → abort.
198
+ - `dry-run` → switch to dry-run mode and print the full diff.
199
+ - `diff <file>` → show the proposed diff for one file, then re-prompt.
200
+
201
+ ## Phase 4 — Apply
202
+
203
+ For `CLAUDE.md`:
204
+ - If fences exist: replace **only** the content between matching
205
+ `<!-- tsykvas-template:start ... -->` and `<!-- tsykvas-template:end -->`
206
+ markers. Leave content above the first marker, between fences, and below
207
+ the last marker untouched.
208
+ - If no fences exist: append the gem's fenced sections after the user's
209
+ existing content, separated by `\n\n---\n\n`. Don't modify user prose.
210
+
211
+ For `.claude/docs/`:
212
+ - `keep-verbatim` files (the 3 gem-canonical + any doc with no placeholders to substitute): no-op.
213
+ - `refresh` files: write the placeholder-substituted content to `.claude/docs/<name>.md`. Do not trim or summarise.
214
+
215
+ ## Phase 5 — Verify (mandatory; failure = roll back)
216
+
217
+ Before declaring success, run all of:
218
+
219
+ 1. **CLAUDE.md ≤ 100 lines (HARD GATE).** Run `wc -l CLAUDE.md`. If
220
+ the result is > 100, the rewrite is rejected — `CLAUDE.md` sits in
221
+ every Claude session's context, so each extra line is a per-prompt
222
+ token tax. Re-plan, re-confirm, then re-apply.
223
+ 2. **Link integrity.** Every `[…](.claude/docs/X.md)` in `CLAUDE.md`
224
+ resolves to a real file. Every slash command listed exists in
225
+ `.claude/commands/`. Every agent listed exists in `.claude/agents/`.
226
+ 3. **Fence balance.** Every `tsykvas-template:start` has a matching
227
+ `tsykvas-template:end`. No unclosed or orphan markers.
228
+ 4. **Code health.** Run `bin/rails zeitwerk:check`.
229
+ 5. **Probe re-run match.** Re-run the probe. The deterministic fields it
230
+ reports should still match the values that drove this rewrite. (If the
231
+ user edited Gemfile during the run, abort.)
232
+
233
+ If any check fails, restore the pre-write state from your in-memory
234
+ snapshot and report which check failed. **Never leave the repo in a
235
+ half-rewritten state.**
236
+
237
+ ## Phase 6 — Self-update
238
+
239
+ If you discover during this run that the gem's shipped templates have
240
+ diverged from what the host needs (e.g., a new must-know rule that should
241
+ live in every project), make a note in your memory file under
242
+ `memory/feedback_*.md` so future runs of this command in other repos start
243
+ from a better baseline.
244
+
245
+ ---
246
+
247
+ ## Constraints
248
+
249
+ - **Never edit content outside fence markers without explicit user
250
+ confirmation.** Treat unfenced content as user-authored.
251
+ - **Never edit `.claude/*.md` or `CLAUDE.md` without the Phase 3 confirmation
252
+ prompt.** No silent runs.
253
+ - **Never skip Phase 0.** The probe is the source of truth.
254
+ - **`CLAUDE.md` must stay ≤ 100 lines.** Hard rule, enforced at Phase 5.
255
+ - Use relative paths for all internal links: `.claude/docs/architecture.md`,
256
+ not absolute URLs.
257
+ - Do not commit. The user runs `/pushit` (or `git commit` themselves) when
258
+ they are happy with the diff.
259
+ - **Preserve gem-canonical docs verbatim.** `tsykvas_rails_template.md`,
260
+ `forms.md`, and `companions.md` ship with the gem and are the canonical
261
+ reference. If a section feels out of date, that's a gem update (bump the
262
+ gem version), not a project tailoring.
@@ -0,0 +1,78 @@
1
+ Check if documentation in `docs/` matches current code changes and update or create docs as needed.
2
+
3
+ ## Step 1: Identify what changed
4
+
5
+ Compare current branch against `main`:
6
+
7
+ ```bash
8
+ git diff main --name-only 2>&1
9
+ ```
10
+
11
+ If working directly on `main` with uncommitted changes:
12
+
13
+ ```bash
14
+ git diff --name-only 2>&1
15
+ git diff --cached --name-only 2>&1
16
+ ```
17
+
18
+ ## Step 2: Understand the changes
19
+
20
+ Read the changed files and understand what flows or features were added or modified. Focus on:
21
+
22
+ - New controllers, operations, components
23
+ - Changed model logic (validations, callbacks, scopes)
24
+ - New or modified routes
25
+ - New mailers or jobs
26
+ - Configuration changes that affect behavior
27
+ - New integrations or external services
28
+
29
+ ## Step 3: Audit existing documentation
30
+
31
+ Check what documentation already exists:
32
+
33
+ ```bash
34
+ find docs/ -name "*.md" -type f 2>&1
35
+ ```
36
+
37
+ For each changed flow, determine:
38
+
39
+ 1. **No doc exists** — a new doc file is needed
40
+ 2. **Doc exists but is outdated** — the doc needs updating
41
+ 3. **Doc exists and is current** — no action needed
42
+
43
+ ## Step 4: Present findings and ask for confirmation
44
+
45
+ Show a table:
46
+
47
+ | Flow / Feature | Doc file | Status | Action needed |
48
+ |----------------|----------|--------|---------------|
49
+ | ... | `docs/...` or *none* | Current / Outdated / Missing | None / Update / Create |
50
+
51
+ Then ask:
52
+
53
+ > Found N doc(s) that need attention. Proceed?
54
+ > 1. Yes, update/create all
55
+ > 2. Let me pick which ones
56
+ > 3. Skip
57
+
58
+ **Wait for user response.** Do NOT make any changes without confirmation.
59
+
60
+ ## Step 5: Update or create documentation
61
+
62
+ For **new docs**:
63
+ - Create in `docs/<domain>/` matching the feature domain (existing domains: `admin`, `crm`, `screener`, `shared`, `base` — or root for cross-cutting)
64
+ - Use clear markdown with sections: overview, how it works, configuration (if any), examples
65
+ - Keep it concise and practical — document behavior, not internal code structure
66
+ - Use the same style and level of detail as existing docs in `docs/` and the template in `.claude/docs/documentation.md`
67
+
68
+ For **existing docs**:
69
+ - Update only the sections affected by the changes
70
+ - Do not rewrite unrelated sections
71
+ - Add new sections if the change introduces new behavior
72
+
73
+ ## Rules
74
+
75
+ - Documentation language: English
76
+ - Never delete documentation without asking
77
+ - Keep docs focused on **what the feature does and how to use it**, not internal code structure
78
+ - If unsure whether a change warrants documentation — include it in the table and let the user decide
@@ -0,0 +1,102 @@
1
+ Check if `.claude/docs/` or `CLAUDE.md` need updating after changes to base classes, application controller, or policies.
2
+
3
+ ## Step 1: Detect changes to watched files
4
+
5
+ Check if any of these files were modified:
6
+
7
+ ```bash
8
+ git diff main --name-only -- \
9
+ app/concepts/base/ \
10
+ app/controllers/concerns/operations_methods.rb \
11
+ app/controllers/application_controller.rb \
12
+ app/policies/application_policy.rb \
13
+ app/policies/admin/base_policy.rb \
14
+ app/policies/crm/base_policy.rb \
15
+ app/policies/screener/base_policy.rb \
16
+ 2>&1
17
+ ```
18
+
19
+ If on `main` with uncommitted changes:
20
+
21
+ ```bash
22
+ git diff --name-only -- \
23
+ app/concepts/base/ \
24
+ app/controllers/concerns/operations_methods.rb \
25
+ app/controllers/application_controller.rb \
26
+ app/policies/application_policy.rb \
27
+ app/policies/admin/base_policy.rb \
28
+ app/policies/crm/base_policy.rb \
29
+ app/policies/screener/base_policy.rb \
30
+ 2>&1
31
+ git diff --cached --name-only -- \
32
+ app/concepts/base/ \
33
+ app/controllers/concerns/operations_methods.rb \
34
+ app/controllers/application_controller.rb \
35
+ app/policies/application_policy.rb \
36
+ app/policies/admin/base_policy.rb \
37
+ app/policies/crm/base_policy.rb \
38
+ app/policies/screener/base_policy.rb \
39
+ 2>&1
40
+ ```
41
+
42
+ **If none of these files changed — stop here. No action needed.**
43
+
44
+ ## Step 2: Understand what changed
45
+
46
+ Read the diffs for each changed file:
47
+
48
+ ```bash
49
+ git diff main -- <file> 2>&1
50
+ ```
51
+
52
+ Understand what was added, removed, or modified in terms of:
53
+
54
+ - New methods or method signatures
55
+ - Changed behavior of existing methods
56
+ - New conventions or patterns
57
+ - Removed or deprecated features
58
+
59
+ ## Step 3: Audit current rules
60
+
61
+ Read the relevant doc files and `CLAUDE.md`. Map each change to the doc file it affects:
62
+
63
+ | Changed file | Doc file |
64
+ |---|---|
65
+ | `app/concepts/base/operation/base.rb` | `.claude/docs/architecture.md`, `.claude/docs/concepts-refactoring.md` |
66
+ | `app/concepts/base/operation/result.rb` | `.claude/docs/architecture.md` |
67
+ | `app/concepts/base/operation/sortable.rb` | `.claude/docs/architecture.md` |
68
+ | `app/concepts/base/component/base.rb` | `.claude/docs/architecture.md`, `.claude/docs/ui-components.md` |
69
+ | `app/concepts/base/component/btn.rb` (or `btn_config.rb`) | `.claude/docs/ui-components.md` |
70
+ | `app/concepts/base/component/table/*.rb` | `.claude/docs/ui-components.md` |
71
+ | `app/concepts/base/component/title_row.rb` | `.claude/docs/ui-components.md` |
72
+ | `app/controllers/concerns/operations_methods.rb` | `.claude/docs/architecture.md`, `.claude/docs/concepts-refactoring.md` |
73
+ | `app/controllers/application_controller.rb` | `CLAUDE.md`, `.claude/docs/architecture.md` |
74
+ | `app/policies/application_policy.rb` | `.claude/docs/architecture.md` |
75
+ | `app/policies/<domain>/base_policy.rb` | `.claude/docs/architecture.md` |
76
+
77
+ ## Step 4: Present proposed changes — MANDATORY
78
+
79
+ **You MUST present a table of all proposed changes and get explicit confirmation before editing ANY file in `.claude/` or `CLAUDE.md`.**
80
+
81
+ Show:
82
+
83
+ | Doc file | Section | Current text (summary) | Proposed change | Why |
84
+ |----------|---------|----------------------|-----------------|-----|
85
+ | ... | ... | ... | ... | ... |
86
+
87
+ Then ask:
88
+
89
+ > Proposed N change(s) to docs/instructions. Apply them?
90
+ > 1. Yes, apply all
91
+ > 2. Let me pick which ones
92
+ > 3. Skip all
93
+
94
+ **Wait for user response. Do NOT make any changes without explicit confirmation.**
95
+
96
+ ## Rules
97
+
98
+ - **NEVER edit `.claude/` or `CLAUDE.md` without user confirmation.** This is non-negotiable.
99
+ - Keep docs concise — do not add unnecessary text that wastes tokens.
100
+ - Only document patterns that Claude needs to follow. If it's obvious from the code, don't add a rule for it.
101
+ - Remove outdated rules when the underlying code changes.
102
+ - Prefer updating existing sections over adding new ones.
@@ -0,0 +1,135 @@
1
+ Audit RSpec coverage for all `.rb` files changed on this branch vs `main`, then write or update specs where coverage is missing.
2
+
3
+ Follow project conventions from `.claude/docs/testing.md` and `.claude/docs/testing-examples.md`.
4
+
5
+ ## Step 1: Find changed `.rb` files
6
+
7
+ ```bash
8
+ git diff main --name-only 2>&1 | grep '\.rb$'
9
+ ```
10
+
11
+ If `main` does not exist as a remote ref, fall back to:
12
+
13
+ ```bash
14
+ git diff origin/main --name-only 2>&1 | grep '\.rb$'
15
+ ```
16
+
17
+ If working directly on `main` with uncommitted changes:
18
+
19
+ ```bash
20
+ git diff --name-only 2>&1 | grep '\.rb$'
21
+ git diff --cached --name-only 2>&1 | grep '\.rb$'
22
+ ```
23
+
24
+ From the output, collect only files under `app/` (skip `spec/`, `db/migrate/`, `config/`, `lib/` unless they contain real business logic).
25
+
26
+ ## Step 2: Filter — skip files with no testable logic
27
+
28
+ For each changed `app/**/*.rb` file, read the actual diff and the full file. **Skip** the file if it matches any of these:
29
+
30
+ - Component `.rb` that only defines `initialize` (parameter wrapper, no methods)
31
+ - Migration file
32
+ - Pure configuration (`config/`, `initializers/`)
33
+ - Empty class with no methods beyond `initialize` and `attr_reader`/`attr_accessor`
34
+ - Route file, `application.rb`, or similar framework glue
35
+
36
+ **Include** everything else: operations, services, models, controllers, jobs, policies, concerns with logic.
37
+
38
+ ## Step 3: Audit each file
39
+
40
+ For every included file, do all three:
41
+
42
+ 1. **Read the diff** — `git diff main -- <file>` — understand exactly what changed or was added
43
+ 2. **Find the spec** — mirror the `app/` path under `spec/`:
44
+ - `app/concepts/admin/user/operation/index.rb` → `spec/concepts/admin/user/operation/index_spec.rb`
45
+ - `app/services/foo.rb` → `spec/services/foo_spec.rb`
46
+ - `app/controllers/admin/users_controller.rb` → `spec/controllers/admin/users_controller_spec.rb` or `spec/requests/admin/users_spec.rb`
47
+ - `app/models/user.rb` → `spec/models/user_spec.rb`
48
+ - `app/jobs/foo_job.rb` → `spec/jobs/foo_job_spec.rb`
49
+ - `app/policies/crm/company_policy.rb` → `spec/policies/crm/company_policy_spec.rb`
50
+ 3. **Verify coverage** — read the spec (if it exists) and confirm every new/changed public method, branch, and business logic path introduced by the diff is tested. Do not assume coverage — read the spec line by line.
51
+
52
+ ## Step 4: Present findings before writing
53
+
54
+ Show a table of files that need action:
55
+
56
+ | File | Spec | Status | Action |
57
+ |------|------|--------|--------|
58
+ | `app/...` | `spec/...` | Missing / Incomplete | Create / Update |
59
+
60
+ Then ask:
61
+
62
+ > Found N file(s) that need test coverage. Proceed?
63
+ > 1. Yes, write/update all
64
+ > 2. Let me pick which ones
65
+ > 3. Skip
66
+
67
+ **Wait for user response before writing any specs.**
68
+
69
+ ## Step 5: Write or update specs
70
+
71
+ Work through each file **one at a time**:
72
+
73
+ ### Writing a new spec
74
+
75
+ - `# frozen_string_literal: true` at the top
76
+ - `require 'rails_helper'`
77
+ - Use `described_class`, not the class name directly
78
+ - Use `let` / `let!`, FactoryBot with Faker
79
+ - Structure: `describe '.call'` → `context 'when ...'` → `it '...'`
80
+ - Cover: happy path, authorization failure (`raise_error(Pundit::NotAuthorizedError)`), error branches, edge cases
81
+ - Declare `type:` explicitly (this project does NOT enable `infer_spec_type_from_file_location!`)
82
+
83
+ ### Updating an existing spec
84
+
85
+ - Add new `context` blocks for new branches; do not rewrite existing passing tests
86
+ - Keep the same describe/context depth and naming style as the rest of the file
87
+
88
+ ### Skip spec creation if:
89
+
90
+ - The file contains only component initialization (no logic methods)
91
+ - The change is cosmetic (rename, whitespace, comment)
92
+
93
+ ## Step 6: Run the specs
94
+
95
+ After writing/updating, run **only the affected spec files**:
96
+
97
+ ```bash
98
+ bundle exec rspec <spec_file_1> <spec_file_2> ... --format documentation 2>&1
99
+ ```
100
+
101
+ Do **not** run the full suite — run only the files you touched.
102
+
103
+ ## Step 7: Fix failures
104
+
105
+ For each failing example:
106
+
107
+ 1. Read the failure message and backtrace
108
+ 2. Read the source file and the spec
109
+ 3. Determine root cause: bug in the spec (wrong stub, wrong expectation) or bug in the source code
110
+ 4. Fix the appropriate file
111
+ 5. Re-run only that spec to confirm: `bundle exec rspec <file>:<line> 2>&1`
112
+
113
+ If a failure reveals a real source code bug — fix the source and note it in the final report.
114
+
115
+ ## Step 8: Report
116
+
117
+ After all specs pass, report:
118
+
119
+ ```
120
+ ## Test Coverage Update
121
+
122
+ | File | Spec | Action taken | Result |
123
+ |------|------|--------------|--------|
124
+ | app/... | spec/... | Created / Updated / Skipped | ✅ X examples, 0 failures |
125
+ ```
126
+
127
+ If any spec still fails after fix attempts — show the failure and ask for guidance.
128
+
129
+ ## Rules
130
+
131
+ - Never run the full suite (`bundle exec rspec`) — run only changed spec files
132
+ - Never delete existing passing tests
133
+ - Use `instance_double` over plain `double` wherever the interface is known
134
+ - Write tests in English
135
+ - Keep tests focused — one logical assertion per `it` block