plutonium 0.45.3 → 0.47.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/skills/plutonium/SKILL.md +150 -0
  3. data/.claude/skills/plutonium-assets/SKILL.md +248 -157
  4. data/.claude/skills/{plutonium-rodauth → plutonium-auth}/SKILL.md +195 -229
  5. data/.claude/skills/plutonium-controller/SKILL.md +9 -2
  6. data/.claude/skills/plutonium-create-resource/SKILL.md +22 -1
  7. data/.claude/skills/plutonium-definition/SKILL.md +521 -7
  8. data/.claude/skills/plutonium-entity-scoping/SKILL.md +317 -0
  9. data/.claude/skills/plutonium-forms/SKILL.md +8 -1
  10. data/.claude/skills/plutonium-installation/SKILL.md +25 -2
  11. data/.claude/skills/plutonium-interaction/SKILL.md +32 -2
  12. data/.claude/skills/plutonium-invites/SKILL.md +11 -7
  13. data/.claude/skills/plutonium-model/SKILL.md +50 -50
  14. data/.claude/skills/plutonium-nested-resources/SKILL.md +18 -1
  15. data/.claude/skills/plutonium-package/SKILL.md +8 -1
  16. data/.claude/skills/plutonium-policy/SKILL.md +69 -78
  17. data/.claude/skills/plutonium-portal/SKILL.md +26 -70
  18. data/.claude/skills/plutonium-testing/SKILL.md +268 -0
  19. data/.claude/skills/plutonium-views/SKILL.md +9 -2
  20. data/.yarnrc.yml +1 -0
  21. data/CHANGELOG.md +38 -0
  22. data/app/assets/plutonium.css +1 -1
  23. data/app/views/rodauth/_login_form.html.erb +0 -3
  24. data/app/views/rodauth/confirm_password.html.erb +0 -4
  25. data/app/views/rodauth/create_account.html.erb +0 -3
  26. data/app/views/rodauth/logout.html.erb +0 -3
  27. data/docs/.vitepress/config.ts +6 -0
  28. data/docs/guides/nested-resources.md +10 -0
  29. data/docs/guides/testing.md +154 -0
  30. data/docs/reference/controller/index.md +9 -4
  31. data/docs/superpowers/plans/2026-04-08-plutonium-skills-overhaul.md +481 -0
  32. data/docs/superpowers/plans/2026-04-14-plutonium-testing.md +2046 -0
  33. data/docs/superpowers/plans/2026-04-14-plutonium-testing.md.tasks.json +21 -0
  34. data/docs/superpowers/specs/2026-04-08-plutonium-skills-overhaul-design.md +236 -0
  35. data/docs/superpowers/specs/2026-04-14-plutonium-testing-design.md +364 -0
  36. data/gemfiles/rails_7.gemfile.lock +1 -1
  37. data/gemfiles/rails_8.0.gemfile.lock +1 -1
  38. data/gemfiles/rails_8.1.gemfile.lock +1 -1
  39. data/lib/generators/pu/core/update/update_generator.rb +8 -0
  40. data/lib/generators/pu/gem/active_shrine/active_shrine_generator.rb +56 -0
  41. data/lib/generators/pu/invites/install_generator.rb +8 -1
  42. data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +43 -0
  43. data/lib/generators/pu/profile/concerns/profile_arguments.rb +10 -4
  44. data/lib/generators/pu/profile/conn_generator.rb +9 -12
  45. data/lib/generators/pu/profile/install_generator.rb +5 -2
  46. data/lib/generators/pu/rodauth/templates/app/rodauth/account_rodauth_plugin.rb.tt +3 -0
  47. data/lib/generators/pu/saas/portal_generator.rb +4 -9
  48. data/lib/generators/pu/saas/welcome/templates/app/views/welcome/onboarding.html.erb.tt +2 -2
  49. data/lib/generators/pu/test/install/install_generator.rb +34 -0
  50. data/lib/generators/pu/test/install/templates/plutonium_testing.rb.tt +14 -0
  51. data/lib/generators/pu/test/scaffold/scaffold_generator.rb +55 -0
  52. data/lib/generators/pu/test/scaffold/templates/integration_test.rb.tt +65 -0
  53. data/lib/plutonium/core/controller.rb +18 -1
  54. data/lib/plutonium/engine.rb +18 -5
  55. data/lib/plutonium/testing/auth_helpers.rb +62 -0
  56. data/lib/plutonium/testing/dsl.rb +73 -0
  57. data/lib/plutonium/testing/nested_resource.rb +58 -0
  58. data/lib/plutonium/testing/portal_access.rb +49 -0
  59. data/lib/plutonium/testing/resource_crud.rb +104 -0
  60. data/lib/plutonium/testing/resource_definition.rb +61 -0
  61. data/lib/plutonium/testing/resource_interaction.rb +51 -0
  62. data/lib/plutonium/testing/resource_model.rb +53 -0
  63. data/lib/plutonium/testing/resource_policy.rb +72 -0
  64. data/lib/plutonium/testing.rb +16 -0
  65. data/lib/plutonium/ui/layout/rodauth_layout.rb +6 -1
  66. data/lib/plutonium/version.rb +1 -1
  67. data/lib/plutonium.rb +2 -0
  68. data/package.json +1 -1
  69. data/yarn.lock +6037 -3893
  70. metadata +27 -8
  71. data/.claude/skills/plutonium/skill.md +0 -130
  72. data/.claude/skills/plutonium-definition-actions/SKILL.md +0 -424
  73. data/.claude/skills/plutonium-definition-query/SKILL.md +0 -364
  74. data/.claude/skills/plutonium-profile/SKILL.md +0 -276
  75. data/.claude/skills/plutonium-theming/SKILL.md +0 -424
@@ -0,0 +1,154 @@
1
+ # Testing
2
+
3
+ Plutonium ships `Plutonium::Testing` — opt-in Minitest concerns that give your app default test coverage for resources, policies, definitions, interactions, models, nested scoping, portal access, and authentication.
4
+
5
+ ## Quick start
6
+
7
+ ```bash
8
+ # Once per app
9
+ rails g pu:test:install
10
+
11
+ # Per resource × portal pairing
12
+ rails g pu:test:scaffold Blogging::Post --portals=admin,org
13
+
14
+ # Run
15
+ bin/rails test
16
+ ```
17
+
18
+ `pu:test:install` adds `require "plutonium/testing"` to `test/test_helper.rb` and creates `test/support/plutonium_testing.rb` (a stub for non-Rodauth auth overrides).
19
+
20
+ `pu:test:scaffold` produces one test file per (resource × portal) pairing with concerns pre-included and stub method bodies pre-filled with `TODO` markers.
21
+
22
+ ## Anatomy of a test file
23
+
24
+ ```ruby
25
+ # test/integration/admin_portal/blogging_post_test.rb
26
+ require "test_helper"
27
+
28
+ class AdminPortal::BloggingPostTest < ActionDispatch::IntegrationTest
29
+ include Plutonium::Testing::ResourceCrud
30
+ include Plutonium::Testing::ResourcePolicy
31
+ include Plutonium::Testing::ResourceDefinition
32
+
33
+ resource_tests_for Blogging::Post, portal: :admin
34
+
35
+ setup do
36
+ @admin = create_admin!
37
+ @org = create_organization!
38
+ @user = create_user!
39
+ login_as(@admin)
40
+ end
41
+
42
+ # --- ResourceCrud stubs ---
43
+ def create_resource!; create_post!(user: @user, organization: @org); end
44
+ def valid_create_params
45
+ {title: "x", body: "y", status: :draft,
46
+ user: @user.to_sgid.to_s, organization: @org.to_sgid.to_s}
47
+ end
48
+ def valid_update_params; {title: "Updated"}; end
49
+
50
+ # --- ResourcePolicy stubs ---
51
+ def policy_roles; {admin: -> { @admin }}; end
52
+ def policy_record; create_post!(user: @user, organization: @org); end
53
+ def policy_matrix
54
+ {index: %i[admin], show: %i[admin], create: %i[admin],
55
+ update: %i[admin], destroy: %i[admin]}
56
+ end
57
+ end
58
+ ```
59
+
60
+ Running this produces 15+ test cases: 7 CRUD + 2 policy + 3 definition + any `skip:` exclusions.
61
+
62
+ ## The DSL
63
+
64
+ Every concern uses the same class-level method:
65
+
66
+ ```ruby
67
+ resource_tests_for ResourceClass,
68
+ portal: :admin, # required
69
+ path_prefix: "/admin", # optional override
70
+ parent: :organization, # for nested resources
71
+ actions: %i[index show new create edit update destroy],
72
+ skip: %i[destroy],
73
+ associated_with: :organization, # ResourceModel only
74
+ sgid_routing: true, # ResourceModel only
75
+ has_cents: %i[price] # ResourceModel only
76
+ ```
77
+
78
+ The **portal symbol** drives path prefix, default auth strategy, and scoping expectations. The resolver walks `Rails.application.routes.routes` for the engine mount — no manual configuration.
79
+
80
+ ## Concerns
81
+
82
+ | Concern | What it generates | Stubs required |
83
+ |---|---|---|
84
+ | `ResourceCrud` | index/show/new/create/edit/update/destroy | `create_resource!`, `valid_create_params`, `valid_update_params` |
85
+ | `ResourcePolicy` | permit? × role × action matrix + relation_scope smoke | `policy_roles`, `policy_record`, `policy_matrix` |
86
+ | `ResourceDefinition` | definition class + defineable prop smoke | none |
87
+ | `ResourceInteraction` | `assert_interaction_success/failure` helpers | `interaction_class`, `valid_interaction_input` |
88
+ | `ResourceModel` | `associated_with`, SGID, `has_cents` | `model_test_record` |
89
+ | `NestedResource` | nested CRUD + sibling-tenant boundaries | `parent_record!`, `other_parent_record!`, `create_resource!(parent:)` |
90
+ | `PortalAccess` | cross-portal access matrix | `login_as_role`, `portal_root_path` |
91
+
92
+ Mix and match — `include` only what you want.
93
+
94
+ ## Auth helpers
95
+
96
+ ```ruby
97
+ login_as(account) # uses portal from DSL
98
+ login_as(account, portal: :admin) # explicit override
99
+ sign_out # uses portal from DSL
100
+ current_account # uses portal from DSL
101
+ with_portal(:org) { ... } # scoped portal switch
102
+ ```
103
+
104
+ ### Non-Rodauth auth
105
+
106
+ Define `sign_in_for_tests(account, portal:)` in your test class (or in `test/support/plutonium_testing.rb` for project-wide use):
107
+
108
+ ```ruby
109
+ def sign_in_for_tests(account, portal:)
110
+ # your custom auth flow here
111
+ post "/your-login", params: {token: account.auth_token}
112
+ end
113
+ ```
114
+
115
+ `AuthHelpers` detects it and defers automatically.
116
+
117
+ ## Generators
118
+
119
+ ### `pu:test:install`
120
+
121
+ Idempotent. Adds the require line and creates the override stub.
122
+
123
+ ### `pu:test:scaffold`
124
+
125
+ | Flag | Default | Purpose |
126
+ |---|---|---|
127
+ | `--portals=admin,org` | required | Emit one file per portal |
128
+ | `--concerns=...` | `crud,policy,definition` | Subset of concerns to include |
129
+ | `--parent=organization` | none | Wires `NestedResource` parent |
130
+ | `--dest=main_app\|<package>` | `main_app` | Output destination |
131
+
132
+ Output: `test/integration/<portal>_portal/<resource>_test.rb`.
133
+
134
+ ## Customization
135
+
136
+ - **Skip individual tests:** `resource_tests_for Klass, portal: :admin, skip: %i[destroy]`
137
+ - **Restrict action set:** `resource_tests_for Klass, portal: :admin, actions: %i[index show]`
138
+ - **Add custom tests:** regular `test "..."` blocks coexist with the generated matrix.
139
+ - **Custom path prefix:** `path_prefix: "/v2/admin"` overrides portal resolution.
140
+
141
+ ## Common pitfalls
142
+
143
+ - **Forgotten stubs raise `NotImplementedError`** with the stub name — look for the missing method.
144
+ - **Portal mismatch:** `:admin` expects `AdminPortal::Engine`. Pass `path_prefix:` if your engine is named differently.
145
+ - **Tenant leakage in stubs:** for an org portal, `create_resource!` must return a record bound to the test's `@org`.
146
+ - **`policy_record` for tenant-scoped resources** must belong to a tenant the role can access — otherwise even allowed roles see `false`.
147
+ - **Nested resources need `parent:` in the DSL AND a parent record** from `parent_record!`. Both are required for path interpolation.
148
+ - **`PortalAccess` uses `portal_access_for`**, not `resource_tests_for`. Don't mix them on the same class.
149
+
150
+ ## See also
151
+
152
+ - [Authorization](/guides/authorization) — write the policy this concern verifies
153
+ - [Multi-tenancy](/guides/multi-tenancy) — entity scoping that drives nested-resource tests
154
+ - [Authentication](/guides/authentication) — Rodauth setup behind the default login flow
@@ -93,10 +93,15 @@ build_collection # Build table component
93
93
  ### URL Generation
94
94
 
95
95
  ```ruby
96
- resource_url_for(@post) # URL for record
97
- resource_url_for(@post, action: :edit) # Edit URL
98
- resource_url_for(Post) # Index URL
99
- resource_url_for(Post, parent: @user) # Nested index URL
96
+ resource_url_for(@post) # URL for record
97
+ resource_url_for(@post, action: :edit) # Edit URL
98
+ resource_url_for(Post) # Index URL
99
+ resource_url_for(Post, parent: @user) # Nested index URL
100
+
101
+ # Interactions (sugar over `action: :interactive_*_action, interactive_action: ...`)
102
+ resource_url_for(@post, interaction: :publish) # Record action
103
+ resource_url_for(Post, interaction: :import) # Resource (class-level) action
104
+ resource_url_for(Post, interaction: :archive, ids: [1, 2]) # Bulk action
100
105
  ```
101
106
 
102
107
  ## Customization Hooks
@@ -0,0 +1,481 @@
1
+ # Plutonium Skills Overhaul Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers-extended-cc:subagent-driven-development (recommended) or superpowers-extended-cc:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Restructure all Plutonium skills so they trigger at the right moments, surface critical anti-patterns first, consolidate cross-cutting concerns (especially entity scoping), and enable greenfield bootstrap loading.
6
+
7
+ **Architecture:** Apply a uniform skill template (description rewrite + 🚨 Critical block + checklist + cross-refs) across all 17 final skills. Merge 3 sets of overlapping skills, create one new `plutonium-entity-scoping` skill, and rewrite the `plutonium` index skill as a router + greenfield bootstrapper.
8
+
9
+ **Tech Stack:** Markdown skill files in `.claude/skills/<name>/SKILL.md`, plus `CLAUDE.md` updates for any references to renamed skills.
10
+
11
+ **User Verification:** NO — this is a documentation/skill refactor. The user requested the overhaul and approved the design; no human-in-the-loop validation is required by the spec. Final review happens via normal git diff.
12
+
13
+ **Spec:** `docs/superpowers/specs/2026-04-08-plutonium-skills-overhaul-design.md`
14
+
15
+ ---
16
+
17
+ ## File map
18
+
19
+ **Skills to delete (after merge):**
20
+ - `.claude/skills/plutonium-definition-actions/`
21
+ - `.claude/skills/plutonium-definition-query/`
22
+ - `.claude/skills/plutonium-profile/`
23
+ - `.claude/skills/plutonium-theming/`
24
+
25
+ **Skills to rename:**
26
+ - `.claude/skills/plutonium-rodauth/` → `.claude/skills/plutonium-auth/`
27
+
28
+ **Skills to create:**
29
+ - `.claude/skills/plutonium-entity-scoping/SKILL.md`
30
+
31
+ **Skills to modify (every remaining skill):**
32
+ - All 17 final skills get description rewrite + 🚨 Critical block + cross-refs.
33
+
34
+ **Other files to check:**
35
+ - `CLAUDE.md` (project root) for references to renamed/deleted skills.
36
+ - `.claude/skills/*/SKILL.md` for cross-references to renamed/deleted skills.
37
+
38
+ ---
39
+
40
+ ## Conventions used by every task
41
+
42
+ **Description format (Phase C):**
43
+ ```
44
+ description: Use BEFORE <verb/construct>. Also when <secondary trigger>. <one-line scope>.
45
+ ```
46
+
47
+ **🚨 Critical block format (Phase D), inserted directly after the H1:**
48
+ ```markdown
49
+ ## 🚨 Critical (read first)
50
+ - **Use the generator.** `pu:<gen>` — never hand-write <X>. <one-line why>.
51
+ - **<Top anti-pattern #1>** — one-line + why.
52
+ - **<Top anti-pattern #2>** — one-line + why.
53
+ - **Related skills:** `plutonium-X` (when Y), `plutonium-Z` (when W).
54
+ ```
55
+
56
+ Cap at ~5 bullets. Pull anti-patterns from existing Gotchas section.
57
+
58
+ **Commit cadence:** one commit per task. Commit message format:
59
+ `docs(skills): <task summary>`
60
+
61
+ ---
62
+
63
+ ## Task 0: Baseline audit
64
+
65
+ **Goal:** Capture the current state so later tasks can verify nothing was lost.
66
+
67
+ **Files:**
68
+ - Read: every `.claude/skills/plutonium-*/SKILL.md`
69
+ - Create: `/tmp/skills-baseline.txt` (line counts + headers index)
70
+
71
+ **Acceptance Criteria:**
72
+ - [ ] Line count for every current skill recorded
73
+ - [ ] List of all H2 headings per skill recorded
74
+ - [ ] List of all `## Gotchas` / anti-pattern bullets per skill recorded
75
+ - [ ] Identified which skills currently mention entity scoping / `associated_with` / `default_relation_scope` / `relation_scope`
76
+
77
+ **Verify:** `wc -l /tmp/skills-baseline.txt` → non-zero
78
+
79
+ **Steps:**
80
+
81
+ - [ ] **Step 1:** Run `wc -l .claude/skills/plutonium-*/SKILL.md` and save.
82
+ - [ ] **Step 2:** For each skill, extract `^## ` headings via Grep.
83
+ - [ ] **Step 3:** Grep `.claude/skills/` for `associated_with|default_relation_scope|relation_scope|entity scoping|entity_scope` to find every mention. This list seeds Task 5 (entity-scoping extraction).
84
+ - [ ] **Step 4:** Grep `.claude/skills/` and `CLAUDE.md` for `plutonium-rodauth|plutonium-profile|plutonium-theming|plutonium-definition-actions|plutonium-definition-query` to find every cross-reference that will need updating.
85
+ - [ ] **Step 5:** Save all findings to `/tmp/skills-baseline.txt`.
86
+ - [ ] **Step 6:** No commit (audit only).
87
+
88
+ ---
89
+
90
+ ## Task 1: Merge plutonium-definition trio
91
+
92
+ **Goal:** Fold `plutonium-definition-actions` and `plutonium-definition-query` into `plutonium-definition` as sections, then delete the source skills.
93
+
94
+ **Files:**
95
+ - Modify: `.claude/skills/plutonium-definition/SKILL.md`
96
+ - Delete: `.claude/skills/plutonium-definition-actions/` (whole directory)
97
+ - Delete: `.claude/skills/plutonium-definition-query/` (whole directory)
98
+
99
+ **Acceptance Criteria:**
100
+ - [ ] `plutonium-definition/SKILL.md` contains all original content from the three skills, organized into sections: §Fields/Inputs/Displays, §Query (search/filters/scopes), §Actions (custom + bulk).
101
+ - [ ] A TOC at the top with anchor links to each section.
102
+ - [ ] No content from the deleted skills is lost (verify by H2-heading diff against baseline).
103
+ - [ ] `plutonium-definition-actions/` and `plutonium-definition-query/` directories no longer exist.
104
+
105
+ **Verify:** `ls .claude/skills/ | grep definition` → only `plutonium-definition`
106
+
107
+ **Steps:**
108
+
109
+ - [ ] **Step 1:** Read all three current skill files in full.
110
+ - [ ] **Step 2:** Plan the new section order. Use this structure:
111
+ ```
112
+ ---
113
+ name: plutonium-definition
114
+ description: <will be rewritten in Phase C — leave existing for now>
115
+ ---
116
+
117
+ # Plutonium Definitions
118
+
119
+ ## Contents
120
+ - [Fields, Inputs, Displays](#fields-inputs-displays)
121
+ - [Query: Search, Filters, Scopes](#query)
122
+ - [Actions: Custom and Bulk](#actions)
123
+ - [Gotchas](#gotchas)
124
+
125
+ <existing plutonium-definition body, retitled as ## Fields, Inputs, Displays>
126
+
127
+ ## Query
128
+ <full body of plutonium-definition-query, with H2s demoted to H3>
129
+
130
+ ## Actions
131
+ <full body of plutonium-definition-actions, with H2s demoted to H3>
132
+
133
+ ## Gotchas
134
+ <merged gotchas from all three>
135
+ ```
136
+ - [ ] **Step 3:** Write the merged file via Write.
137
+ - [ ] **Step 4:** Delete the two source directories: `rm -rf .claude/skills/plutonium-definition-actions .claude/skills/plutonium-definition-query`
138
+ - [ ] **Step 5:** Verify with `ls .claude/skills/ | grep definition`.
139
+ - [ ] **Step 6:** Commit: `docs(skills): merge definition-actions and definition-query into plutonium-definition`
140
+
141
+ ---
142
+
143
+ ## Task 2: Merge plutonium-profile into plutonium-rodauth, rename to plutonium-auth
144
+
145
+ **Goal:** Combine rodauth and profile content into a single `plutonium-auth` skill.
146
+
147
+ **Files:**
148
+ - Modify: `.claude/skills/plutonium-rodauth/SKILL.md` (will be moved)
149
+ - Delete: `.claude/skills/plutonium-profile/` (whole directory)
150
+ - Rename: `.claude/skills/plutonium-rodauth/` → `.claude/skills/plutonium-auth/`
151
+
152
+ **Acceptance Criteria:**
153
+ - [ ] All content from `plutonium-rodauth` and `plutonium-profile` lives in `.claude/skills/plutonium-auth/SKILL.md`.
154
+ - [ ] Sectioned: §Rodauth setup · §Account types · §Profile page.
155
+ - [ ] `name:` frontmatter updated to `plutonium-auth`.
156
+ - [ ] TOC at top.
157
+ - [ ] Old directories no longer exist.
158
+
159
+ **Verify:** `ls .claude/skills/ | grep -E 'auth|rodauth|profile'` → only `plutonium-auth`
160
+
161
+ **Steps:**
162
+
163
+ - [ ] **Step 1:** Read both current skill files.
164
+ - [ ] **Step 2:** Construct merged file body with TOC + 3 sections + merged gotchas.
165
+ - [ ] **Step 3:** `mv .claude/skills/plutonium-rodauth .claude/skills/plutonium-auth`
166
+ - [ ] **Step 4:** Write merged content to `.claude/skills/plutonium-auth/SKILL.md`, updating `name: plutonium-auth` in frontmatter.
167
+ - [ ] **Step 5:** `rm -rf .claude/skills/plutonium-profile`
168
+ - [ ] **Step 6:** Verify with `ls .claude/skills/`.
169
+ - [ ] **Step 7:** Commit: `docs(skills): merge plutonium-profile into plutonium-rodauth, rename to plutonium-auth`
170
+
171
+ ---
172
+
173
+ ## Task 3: Merge plutonium-theming into plutonium-assets
174
+
175
+ **Goal:** Fold theming content into assets as a section.
176
+
177
+ **Files:**
178
+ - Modify: `.claude/skills/plutonium-assets/SKILL.md`
179
+ - Delete: `.claude/skills/plutonium-theming/`
180
+
181
+ **Acceptance Criteria:**
182
+ - [ ] `plutonium-assets/SKILL.md` contains all theming content as §Design tokens / theming.
183
+ - [ ] Sectioned: §Tailwind/CSS · §Stimulus registration · §Design tokens & theming.
184
+ - [ ] TOC at top.
185
+ - [ ] `plutonium-theming/` no longer exists.
186
+
187
+ **Verify:** `ls .claude/skills/ | grep -E 'assets|theming'` → only `plutonium-assets`
188
+
189
+ **Steps:**
190
+
191
+ - [ ] **Step 1:** Read both source files.
192
+ - [ ] **Step 2:** Build merged structure with TOC.
193
+ - [ ] **Step 3:** Write merged file.
194
+ - [ ] **Step 4:** `rm -rf .claude/skills/plutonium-theming`
195
+ - [ ] **Step 5:** Verify.
196
+ - [ ] **Step 6:** Commit: `docs(skills): merge plutonium-theming into plutonium-assets`
197
+
198
+ ---
199
+
200
+ ## Task 4: Update cross-references to merged/renamed skills
201
+
202
+ **Goal:** Find and update every reference to the deleted/renamed skills throughout the repo.
203
+
204
+ **Files:**
205
+ - Modify: any file matching the grep results from Task 0 step 4.
206
+ - Likely candidates: `CLAUDE.md`, other `.claude/skills/*/SKILL.md`, `docs/`.
207
+
208
+ **Acceptance Criteria:**
209
+ - [ ] No references remain to `plutonium-rodauth`, `plutonium-profile`, `plutonium-theming`, `plutonium-definition-actions`, `plutonium-definition-query`.
210
+ - [ ] References point to the new names (`plutonium-auth`, `plutonium-definition`, `plutonium-assets`).
211
+
212
+ **Verify:**
213
+ ```bash
214
+ grep -r 'plutonium-rodauth\|plutonium-profile\|plutonium-theming\|plutonium-definition-actions\|plutonium-definition-query' .claude/ CLAUDE.md docs/ 2>/dev/null
215
+ ```
216
+ Expected: no output.
217
+
218
+ **Steps:**
219
+
220
+ - [ ] **Step 1:** Run the verify grep above.
221
+ - [ ] **Step 2:** For each match, Edit the file to update the reference.
222
+ - [ ] **Step 3:** Re-run grep until empty.
223
+ - [ ] **Step 4:** Commit: `docs(skills): update cross-references after skill merges/renames`
224
+
225
+ ---
226
+
227
+ ## Task 5: Create plutonium-entity-scoping skill
228
+
229
+ **Goal:** Single source of truth for entity scoping. Extract scoping content from `plutonium-model`, `plutonium-policy`, `plutonium-portal`, `plutonium-invites` and consolidate here. Add worked examples for the three model shapes.
230
+
231
+ **Files:**
232
+ - Create: `.claude/skills/plutonium-entity-scoping/SKILL.md`
233
+ - Modify (in Task 8 cross-ref pass, not here): the four source skills get a teaser + link.
234
+
235
+ **Acceptance Criteria:**
236
+ - [ ] Skill exists with the standard template structure.
237
+ - [ ] Description: `Use BEFORE writing relation_scope, associated_with, scoping a model to a tenant, or any multi-tenancy work. Also when configuring entity strategies on a portal. The single source of truth for Plutonium entity scoping.`
238
+ - [ ] 🚨 Critical block lists: never bypass `default_relation_scope`, always declare `associated_with`, use a generator to scaffold scoped resources.
239
+ - [ ] Quick checklist for "scope a new model to a tenant".
240
+ - [ ] Sections: §How entity scoping works · §`associated_with` resolution · §`default_relation_scope` and safe `relation_scope` overrides · §Entity strategies (path, custom) · §Three model shapes (worked examples).
241
+ - [ ] Three model-shape worked examples: (a) direct child `Comment belongs_to :post belongs_to :tenant`, (b) join table `Membership` linking user/tenant, (c) grandchild `Comment` → `Post` → `Tenant`.
242
+ - [ ] Cross-refs to `plutonium-model`, `plutonium-policy`, `plutonium-portal`, `plutonium-invites`.
243
+
244
+ **Verify:** `cat .claude/skills/plutonium-entity-scoping/SKILL.md | wc -l` → > 100
245
+
246
+ **Steps:**
247
+
248
+ - [ ] **Step 1:** Re-read the entity-scoping bits from `plutonium-model`, `plutonium-policy`, `plutonium-portal`, `plutonium-invites` (use the seed list from Task 0 step 3).
249
+ - [ ] **Step 2:** Draft the file using the standard skill template.
250
+ - [ ] **Step 3:** Write the three model-shape examples. Direct child is the existing `Comment/Post` example; for join-table show a `Membership` model with `belongs_to :user, belongs_to :tenant` and `has_one :tenant, through: :membership` on `User`; for grandchild show `Comment.has_one :tenant, through: :post` and how `associated_with` resolves it.
251
+ - [ ] **Step 4:** Write the file.
252
+ - [ ] **Step 5:** Verify line count.
253
+ - [ ] **Step 6:** Commit: `docs(skills): add plutonium-entity-scoping skill`
254
+
255
+ ---
256
+
257
+ ## Task 6: Rewrite descriptions for all 17 skills
258
+
259
+ **Goal:** Every skill's `description:` frontmatter follows `Use BEFORE <verb/construct>. Also when <secondary>. <scope>.`
260
+
261
+ **Files:**
262
+ - Modify: frontmatter in all 17 `.claude/skills/plutonium-*/SKILL.md` files.
263
+
264
+ **Acceptance Criteria:**
265
+ - [ ] Every description starts with "Use BEFORE".
266
+ - [ ] Each description names at least one specific code construct, generator, or file the agent might be about to touch.
267
+ - [ ] No description is a topic-noun list.
268
+
269
+ **Verify:**
270
+ ```bash
271
+ grep -h '^description:' .claude/skills/plutonium-*/SKILL.md | grep -v 'Use BEFORE\|Use when starting\|Use when'
272
+ ```
273
+ Expected: empty (or only the index skill, which has its own format).
274
+
275
+ **Steps:**
276
+
277
+ - [ ] **Step 1:** For each skill, draft new description using this table as a starting point. **The drafts below are starting points — adjust if reading the skill reveals a more specific trigger.**
278
+
279
+ | Skill | Draft description |
280
+ |---|---|
281
+ | `plutonium` | `Use BEFORE starting any Plutonium work — new app, new feature, or first edit in an unfamiliar area. Routes you to the right skills and bootstraps greenfield work.` |
282
+ | `plutonium-installation` | `Use BEFORE installing Plutonium in a Rails app or running pu:install. Also when configuring initial Plutonium setup. Covers generators, gemfile, and initial config.` |
283
+ | `plutonium-create-resource` | `Use BEFORE running pu:res:scaffold or creating any new resource. Also when picking field types for a generator. Covers field syntax and scaffold options.` |
284
+ | `plutonium-model` | `Use BEFORE editing a Plutonium resource model, adding associations, has_cents, SGID, or routing helpers. For tenancy, see plutonium-entity-scoping.` |
285
+ | `plutonium-policy` | `Use BEFORE writing relation_scope, permitted_attributes, permitted_associations, or any policy override. For tenant-scoped relation_scope, also load plutonium-entity-scoping.` |
286
+ | `plutonium-entity-scoping` | (already set in Task 5) |
287
+ | `plutonium-controller` | `Use BEFORE overriding a controller action, adding a hook, or changing redirect logic in a Plutonium controller.` |
288
+ | `plutonium-interaction` | `Use BEFORE writing an interaction class, encapsulating business logic, or building multi-step operations beyond basic CRUD.` |
289
+ | `plutonium-definition` | `Use BEFORE editing a resource definition — adding fields, inputs, displays, search, filters, scopes, custom actions, or bulk actions.` |
290
+ | `plutonium-views` | `Use BEFORE building a custom page, panel, table, layout, or Phlex component in Plutonium.` |
291
+ | `plutonium-forms` | `Use BEFORE customizing a form template, field builder, or input component in Plutonium.` |
292
+ | `plutonium-assets` | `Use BEFORE configuring Tailwind, registering a Stimulus controller, or editing design tokens / theming in a Plutonium app.` |
293
+ | `plutonium-auth` | `Use BEFORE configuring Rodauth, account types, login flows, or building a profile / account settings page.` |
294
+ | `plutonium-invites` | `Use BEFORE setting up user invitations or entity membership in a multi-tenant Plutonium app. Also load plutonium-entity-scoping.` |
295
+ | `plutonium-portal` | `Use BEFORE creating a portal, mounting a portal engine, configuring entity strategies, or routing portal-specific resources.` |
296
+ | `plutonium-package` | `Use BEFORE creating a feature package or portal package, or organizing a Plutonium app into modular engines.` |
297
+ | `plutonium-nested-resources` | `Use BEFORE configuring parent/child resource relationships, nested routes, or scoped URL generation.` |
298
+
299
+ - [ ] **Step 2:** For each skill, Edit the `description:` line in the frontmatter.
300
+ - [ ] **Step 3:** Run the verify grep.
301
+ - [ ] **Step 4:** Commit: `docs(skills): rewrite descriptions to trigger on verbs and constructs`
302
+
303
+ ---
304
+
305
+ ## Task 7: Add 🚨 Critical block to all 17 skills
306
+
307
+ **Goal:** Every skill gets a fixed-position 🚨 Critical block right after the H1.
308
+
309
+ **Files:**
310
+ - Modify: all 17 `.claude/skills/plutonium-*/SKILL.md` files.
311
+
312
+ **Acceptance Criteria:**
313
+ - [ ] Every skill has `## 🚨 Critical (read first)` as the first H2 after the H1.
314
+ - [ ] Each block contains: generator-first bullet (where applicable), 1-2 top anti-patterns pulled from gotchas, and a "Related skills" bullet with 1-3 cross-refs.
315
+ - [ ] Cap: ~5 bullets per block.
316
+ - [ ] Existing Gotchas sections are kept (not deleted) — top items are duplicated to the 🚨 block.
317
+
318
+ **Verify:**
319
+ ```bash
320
+ for f in .claude/skills/plutonium-*/SKILL.md; do
321
+ head -30 "$f" | grep -q '🚨 Critical' || echo "MISSING: $f"
322
+ done
323
+ ```
324
+ Expected: no output.
325
+
326
+ **Steps:**
327
+
328
+ - [ ] **Step 1:** For each skill, read the file and identify (a) does it have a generator? (b) what are the top 1-2 anti-patterns from existing gotchas? (c) which other skills does it relate to?
329
+ - [ ] **Step 2:** Write a 🚨 block following the convention. Example for `plutonium-policy`:
330
+ ```markdown
331
+ ## 🚨 Critical (read first)
332
+ - **Use generators.** `pu:res:scaffold` and `pu:res:conn` create policies — never hand-write policy files.
333
+ - **Never bypass `default_relation_scope`.** Overriding `relation_scope` with a raw `where(...)` skips entity scoping and leaks tenant data. Always compose with `super` or use `associated_with`.
334
+ - **Derived actions inherit.** `update?` falls back to `create?` unless overridden — don't duplicate.
335
+ - **Related skills:** `plutonium-entity-scoping` (for tenant-scoped overrides), `plutonium-model` (for `associated_with`), `plutonium-definition` (for `permitted_attributes` location).
336
+ ```
337
+ - [ ] **Step 3:** Edit each skill to insert the block after the H1 (before the first existing H2).
338
+ - [ ] **Step 4:** Run the verify loop.
339
+ - [ ] **Step 5:** Commit: `docs(skills): add 🚨 Critical block to every skill`
340
+
341
+ ---
342
+
343
+ ## Task 8: Add cross-references back to source skills (entity-scoping teasers)
344
+
345
+ **Goal:** Every skill that previously held entity-scoping content now has a one-paragraph teaser + link to `plutonium-entity-scoping`. Prevents drift and content duplication.
346
+
347
+ **Files:**
348
+ - Modify: `.claude/skills/plutonium-model/SKILL.md`
349
+ - Modify: `.claude/skills/plutonium-policy/SKILL.md`
350
+ - Modify: `.claude/skills/plutonium-portal/SKILL.md`
351
+ - Modify: `.claude/skills/plutonium-invites/SKILL.md`
352
+
353
+ **Acceptance Criteria:**
354
+ - [ ] Each of the four skills has a "## Entity scoping" section (or similar) that contains: a one-paragraph summary of how that skill relates to entity scoping, and an explicit link to `plutonium-entity-scoping` as the authoritative source.
355
+ - [ ] The 🚨 block of each of these four skills mentions `plutonium-entity-scoping` in the Related bullet.
356
+ - [ ] Long-form scoping content in the source skills is replaced by the teaser + link, OR retained but explicitly marked "see plutonium-entity-scoping for the canonical version".
357
+
358
+ **Verify:**
359
+ ```bash
360
+ for f in plutonium-model plutonium-policy plutonium-portal plutonium-invites; do
361
+ grep -q 'plutonium-entity-scoping' .claude/skills/$f/SKILL.md || echo "MISSING: $f"
362
+ done
363
+ ```
364
+ Expected: no output.
365
+
366
+ **Steps:**
367
+
368
+ - [ ] **Step 1:** For each of the four files, find the existing entity-scoping section (using the seed list from Task 0).
369
+ - [ ] **Step 2:** Replace it with a teaser paragraph ending in: `> **For entity scoping details, see the [plutonium-entity-scoping](../plutonium-entity-scoping/SKILL.md) skill — it is the single source of truth.**`
370
+ - [ ] **Step 3:** Verify the 🚨 block (added in Task 7) already lists `plutonium-entity-scoping` as related; if not, add it.
371
+ - [ ] **Step 4:** Run the verify loop.
372
+ - [ ] **Step 5:** Commit: `docs(skills): defer entity-scoping content to plutonium-entity-scoping`
373
+
374
+ ---
375
+
376
+ ## Task 9: Add Quick checklist sections to bootstrap + high-traffic skills
377
+
378
+ **Goal:** The 7 highest-traffic skills get a "## Quick checklist" section so agents can convert them to tasks via TaskCreate.
379
+
380
+ **Files (7 skills):**
381
+ - Modify: `.claude/skills/plutonium-installation/SKILL.md`
382
+ - Modify: `.claude/skills/plutonium-create-resource/SKILL.md`
383
+ - Modify: `.claude/skills/plutonium-model/SKILL.md`
384
+ - Modify: `.claude/skills/plutonium-policy/SKILL.md`
385
+ - Modify: `.claude/skills/plutonium-portal/SKILL.md`
386
+ - Modify: `.claude/skills/plutonium-definition/SKILL.md`
387
+ - Modify: `.claude/skills/plutonium-entity-scoping/SKILL.md`
388
+
389
+ **Acceptance Criteria:**
390
+ - [ ] Each of the 7 skills has a `## Quick checklist` section with a numbered list (5-10 items) describing the most common workflow for that skill.
391
+ - [ ] Checklist items are imperative and concrete (e.g., "Run `pu:res:scaffold` with the appropriate field types"), not vague ("Set up the model").
392
+ - [ ] Section is placed after 🚨 Critical and before the long-form sections.
393
+
394
+ **Verify:**
395
+ ```bash
396
+ for f in plutonium-installation plutonium-create-resource plutonium-model plutonium-policy plutonium-portal plutonium-definition plutonium-entity-scoping; do
397
+ grep -q '## Quick checklist' .claude/skills/$f/SKILL.md || echo "MISSING: $f"
398
+ done
399
+ ```
400
+ Expected: no output.
401
+
402
+ **Steps:**
403
+
404
+ - [ ] **Step 1:** For each of the 7 skills, draft a 5-10 item checklist for "the most common workflow." For example, `plutonium-create-resource`'s checklist would be: 1) Pick a portal/dest, 2) Identify field types, 3) Run `pu:res:scaffold ResourceName field:type ...`, 4) Run migrations, 5) Connect to a portal via `pu:res:conn`, 6) Verify with `bin/rails routes | grep <resource>`, 7) Open the portal route in the browser.
405
+ - [ ] **Step 2:** Edit each file to insert the section.
406
+ - [ ] **Step 3:** Run the verify loop.
407
+ - [ ] **Step 4:** Commit: `docs(skills): add Quick checklist sections to bootstrap and high-traffic skills`
408
+
409
+ ---
410
+
411
+ ## Task 10: Rewrite the `plutonium` index skill as router + bootstrapper
412
+
413
+ **Goal:** The index skill becomes a router table, a greenfield bootstrap bundle, and a generator catalog.
414
+
415
+ **Files:**
416
+ - Modify: `.claude/skills/plutonium/SKILL.md` (full rewrite)
417
+
418
+ **Acceptance Criteria:**
419
+ - [ ] Description set per Task 6 table.
420
+ - [ ] 🚨 block at top with generator-first message and bootstrap pointer.
421
+ - [ ] Greenfield bootstrap bundle section listing the 7 foundational skills (installation, create-resource, model, policy, entity-scoping, portal, definition) with explicit triggers.
422
+ - [ ] Router table mapping "About to..." actions to the right skill(s).
423
+ - [ ] Generator catalog: table of `pu:*` generators with one-line purpose + which skill covers it.
424
+ - [ ] Multi-tenancy entries in the router table cross-reference `plutonium-entity-scoping`.
425
+
426
+ **Verify:**
427
+ ```bash
428
+ grep -c 'plutonium-' .claude/skills/plutonium/SKILL.md
429
+ ```
430
+ Expected: at least 17 (one mention per other skill).
431
+
432
+ **Steps:**
433
+
434
+ - [ ] **Step 1:** Read the spec's full `plutonium` index template (Section 4 in the design doc).
435
+ - [ ] **Step 2:** Run `bin/rails generate --help 2>&1 | grep '^ pu:'` from `test/dummy/` to enumerate generators. If that fails, list them by reading `lib/generators/pu/`.
436
+ - [ ] **Step 3:** Build the generator catalog table.
437
+ - [ ] **Step 4:** Write the full new file body following the template in the spec.
438
+ - [ ] **Step 5:** Verify with the grep.
439
+ - [ ] **Step 6:** Commit: `docs(skills): rewrite plutonium index as router and greenfield bootstrapper`
440
+
441
+ ---
442
+
443
+ ## Task 11: Final verification sweep
444
+
445
+ **Goal:** Catch any drift, missing pieces, or broken cross-references introduced during the overhaul.
446
+
447
+ **Files:**
448
+ - Read-only checks across `.claude/skills/`.
449
+
450
+ **Acceptance Criteria:**
451
+ - [ ] All 17 expected skills exist; no extras.
452
+ - [ ] All 17 skills have a 🚨 block.
453
+ - [ ] All 17 skills have a description starting with "Use BEFORE" (or the index's variant).
454
+ - [ ] No references to deleted/renamed skills anywhere in `.claude/`, `CLAUDE.md`, or `docs/`.
455
+ - [ ] `plutonium-entity-scoping` exists and has the three model-shape examples.
456
+ - [ ] `plutonium` index lists all 17 skills somewhere (router table + bootstrap bundle).
457
+
458
+ **Verify:**
459
+ ```bash
460
+ ls .claude/skills/ | grep -c '^plutonium' # → 17
461
+ grep -L '🚨 Critical' .claude/skills/plutonium-*/SKILL.md # → empty
462
+ grep -L '^description: Use BEFORE\|^description: Use when starting' .claude/skills/plutonium-*/SKILL.md # → empty
463
+ grep -r 'plutonium-rodauth\|plutonium-profile\|plutonium-theming\|plutonium-definition-actions\|plutonium-definition-query' .claude/ CLAUDE.md docs/ 2>/dev/null # → empty
464
+ ```
465
+
466
+ **Steps:**
467
+
468
+ - [ ] **Step 1:** Run all four verify commands.
469
+ - [ ] **Step 2:** Fix any failures inline.
470
+ - [ ] **Step 3:** Re-run until all pass.
471
+ - [ ] **Step 4:** Commit (only if fixes were made): `docs(skills): final verification fixes for skills overhaul`
472
+
473
+ ---
474
+
475
+ ## Self-review
476
+
477
+ - Spec coverage: ✓ all 7 phases (A-G) of the spec map to tasks 1-10; Task 0 is the audit; Task 11 is the final sweep.
478
+ - Placeholder scan: ✓ no TBDs; descriptions table provides starting points but instructs the implementer to adjust based on reading.
479
+ - Type consistency: N/A (no code).
480
+ - Verification requirement scan: NO — no user verification required.
481
+