@fluentcommerce/ai-skills 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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +622 -0
  3. package/bin/cli.mjs +1973 -0
  4. package/content/cli/agents/fluent-cli/agent.json +149 -0
  5. package/content/cli/agents/fluent-cli.md +132 -0
  6. package/content/cli/skills/fluent-bootstrap/SKILL.md +181 -0
  7. package/content/cli/skills/fluent-cli-index/SKILL.md +63 -0
  8. package/content/cli/skills/fluent-cli-mcp-cicd/SKILL.md +77 -0
  9. package/content/cli/skills/fluent-cli-reference/SKILL.md +1031 -0
  10. package/content/cli/skills/fluent-cli-retailer/SKILL.md +85 -0
  11. package/content/cli/skills/fluent-cli-settings/SKILL.md +106 -0
  12. package/content/cli/skills/fluent-connect/SKILL.md +886 -0
  13. package/content/cli/skills/fluent-module-deploy/SKILL.md +349 -0
  14. package/content/cli/skills/fluent-profile/SKILL.md +180 -0
  15. package/content/cli/skills/fluent-workflow/SKILL.md +310 -0
  16. package/content/dev/agents/fluent-dev/agent.json +88 -0
  17. package/content/dev/agents/fluent-dev.md +525 -0
  18. package/content/dev/reference-modules/catalog.json +4754 -0
  19. package/content/dev/skills/fluent-build/SKILL.md +192 -0
  20. package/content/dev/skills/fluent-connection-analysis/SKILL.md +386 -0
  21. package/content/dev/skills/fluent-custom-code/SKILL.md +895 -0
  22. package/content/dev/skills/fluent-data-module-scaffold/SKILL.md +714 -0
  23. package/content/dev/skills/fluent-e2e-test/SKILL.md +394 -0
  24. package/content/dev/skills/fluent-event-api/SKILL.md +945 -0
  25. package/content/dev/skills/fluent-feature-explain/SKILL.md +603 -0
  26. package/content/dev/skills/fluent-feature-plan/PLAN_TEMPLATE.md +695 -0
  27. package/content/dev/skills/fluent-feature-plan/SKILL.md +227 -0
  28. package/content/dev/skills/fluent-job-batch/SKILL.md +138 -0
  29. package/content/dev/skills/fluent-mermaid-validate/SKILL.md +86 -0
  30. package/content/dev/skills/fluent-module-scaffold/SKILL.md +1928 -0
  31. package/content/dev/skills/fluent-module-validate/SKILL.md +775 -0
  32. package/content/dev/skills/fluent-pre-deploy-check/SKILL.md +1108 -0
  33. package/content/dev/skills/fluent-retailer-config/SKILL.md +1111 -0
  34. package/content/dev/skills/fluent-rule-scaffold/SKILL.md +385 -0
  35. package/content/dev/skills/fluent-scope-decompose/SKILL.md +1021 -0
  36. package/content/dev/skills/fluent-session-audit-export/SKILL.md +632 -0
  37. package/content/dev/skills/fluent-session-summary/SKILL.md +195 -0
  38. package/content/dev/skills/fluent-settings/SKILL.md +1058 -0
  39. package/content/dev/skills/fluent-source-onboard/SKILL.md +632 -0
  40. package/content/dev/skills/fluent-system-monitoring/SKILL.md +767 -0
  41. package/content/dev/skills/fluent-test-data/SKILL.md +513 -0
  42. package/content/dev/skills/fluent-trace/SKILL.md +1143 -0
  43. package/content/dev/skills/fluent-transition-api/SKILL.md +346 -0
  44. package/content/dev/skills/fluent-version-manage/SKILL.md +744 -0
  45. package/content/dev/skills/fluent-workflow-analyzer/SKILL.md +959 -0
  46. package/content/dev/skills/fluent-workflow-builder/SKILL.md +319 -0
  47. package/content/dev/skills/fluent-workflow-deploy/SKILL.md +267 -0
  48. package/content/mcp-extn/agents/fluent-mcp.md +69 -0
  49. package/content/mcp-extn/skills/fluent-mcp-tools/SKILL.md +461 -0
  50. package/content/mcp-official/agents/fluent-mcp-core.md +91 -0
  51. package/content/mcp-official/skills/fluent-mcp-core/SKILL.md +94 -0
  52. package/content/rfl/agents/fluent-rfl.md +56 -0
  53. package/content/rfl/skills/fluent-rfl-assess/SKILL.md +172 -0
  54. package/docs/CAPABILITY_MAP.md +77 -0
  55. package/docs/CLI_COVERAGE.md +47 -0
  56. package/docs/DEV_WORKFLOW.md +802 -0
  57. package/docs/FLOW_RUN.md +142 -0
  58. package/docs/USE_CASES.md +404 -0
  59. package/metadata.json +156 -0
  60. package/package.json +51 -0
@@ -0,0 +1,895 @@
1
+ ---
2
+ name: fluent-custom-code
3
+ description: Analyze custom Fluent implementation source code under accounts/<PROFILE>/SOURCE, explain behavior, and prepare safe extension plans even when repo/module layout is non-standard. Triggers on "analyze custom code", "explain this plugin", "extend rule logic", "understand source", "non-standard module structure".
4
+ user-invocable: true
5
+ allowed-tools: Bash, Read, Write, Edit, Glob, Grep
6
+ argument-hint: <PROFILE> [--retailer <RETAILER_REF>] [--objective "<what to change>"]
7
+ ---
8
+
9
+ # Custom Code Intelligence
10
+
11
+ Understand and extend custom Fluent implementation code safely, even when repo layout does not follow standard Fluent module structure.
12
+
13
+ ## Ownership Boundary
14
+
15
+ This skill owns source discovery, code mapping, behavior explanation, and extension readiness for custom repos.
16
+
17
+ - Workflow structure analysis is owned by `/fluent-workflow-analyzer`.
18
+ - Runtime failure tracing is owned by `/fluent-trace`.
19
+ - Workflow editing is owned by `/fluent-workflow-builder`.
20
+
21
+ ## When to Use
22
+
23
+ - "Explain what this custom code does end-to-end"
24
+ - "Which class/rule handles this behavior?"
25
+ - "How can we extend this logic safely?"
26
+ - Source layout is unclear, nested, or non-standard
27
+
28
+ ## Required Inputs
29
+
30
+ 1. `PROFILE` (maps to `accounts/<PROFILE>/`)
31
+ 2. Optional `RETAILER_REF` (needed to download workflows if missing)
32
+ 3. Optional objective (what behavior to explain or extend)
33
+
34
+ ## Workspace Convention
35
+
36
+ Primary paths:
37
+
38
+ - Source repos: `accounts/<PROFILE>/SOURCE/`
39
+ - Workflow JSONs: `accounts/<PROFILE>/workflows/<RETAILER_REF>/`
40
+
41
+ If `accounts/<PROFILE>/workflows/<RETAILER_REF>/` is missing or empty, download first:
42
+
43
+ ```bash
44
+ fluent workflow list -p <PROFILE> -r <RETAILER_REF>
45
+ fluent workflow download -p <PROFILE> -r <RETAILER_REF> -w all -o accounts/<PROFILE>/workflows/<RETAILER_REF>/
46
+ ```
47
+
48
+ If the host OS cannot write workflow files containing reserved characters (for example `::` on Windows), export JSON and normalize file names:
49
+
50
+ ```bash
51
+ fluent workflow download -p <PROFILE> -r <RETAILER_REF> -w all --json > accounts/<PROFILE>/workflows/<RETAILER_REF>/workflows-raw.json
52
+ ```
53
+
54
+ Then split into one file per workflow with sanitized names, and persist `workflow-file-map.json` (original workflow name -> sanitized filename).
55
+
56
+ If `RETAILER_REF` is omitted and multiple retailer folders exist under `accounts/<PROFILE>/workflows/`, require explicit retailer selection before analysis.
57
+
58
+ ### Account intake contract
59
+
60
+ Treat `accounts/<PROFILE>/` as the single analysis workspace for that account:
61
+
62
+ - `accounts/<PROFILE>/SOURCE/` may contain:
63
+ - editable source repos (`module.json`, `src/main/java`, tests)
64
+ - read-only deployment artifacts (`*.jar`, `*.zip`)
65
+ - `accounts/<PROFILE>/workflows/<RETAILER_REF>/` contains downloaded workflow JSON baselines.
66
+ - `accounts/<PROFILE>/workflows/<RETAILER_REF>/workflow-context.json` captures the owning profile + retailer and must match analysis target.
67
+ - `accounts/<PROFILE>/analysis/` contains generated analysis artifacts for reuse.
68
+
69
+ The analysis objective is a holistic inventory:
70
+
71
+ 1. What custom rules exist (source + decompiled artifacts).
72
+ 2. What is deployed/available (installed rules snapshot and workflow references).
73
+ 3. What can be safely reused vs what needs new code.
74
+ 4. What remains unknown and needs additional source input.
75
+
76
+ ### Pre-Check: Context Verification and Module Inventory
77
+
78
+ **Verify MCP target matches analysis profile:** Run `config.validate` via MCP. If the `baseUrl` points at a different account than `<PROFILE>`, the MCP `plugin.list` results will carry the wrong `<ACCOUNT>` prefix. In that case, use the Fluent CLI instead: `fluent module list -p <PROFILE>`.
79
+
80
+ **Discover all retailers:** A single profile may serve multiple retailers with different workflows. Enumerate retailer configs (`~/.fluentcommerce/<PROFILE>/retailer.*.json`) and list workflows per retailer. Download workflows for all retailers that have deployed content.
81
+
82
+ **Check module inventory:** Before scanning source, check if a module inventory exists:
83
+
84
+ ```
85
+ accounts/<PROFILE>/analysis/module-validate/module-inventory.json
86
+ ```
87
+
88
+ If found, read it to identify:
89
+ - Which modules are `customExtension` (have rules to analyze)
90
+ - Which have `hasSource: true` (source available under SOURCE/)
91
+ - Which have `hasSource: false` (need JAR/ZIP decompilation)
92
+ - The `sourceDir` for each module (exact path to source root)
93
+
94
+ If missing, recommend running `/fluent-module-validate inventory` first.
95
+
96
+ This pre-check avoids scanning for modules that are reference (no custom code) or data-only (no rules).
97
+
98
+ ## Artifact Generation Sequence
99
+
100
+ Follow this order to ensure all dependencies are available:
101
+
102
+ ```
103
+ Phase 1: Input Validation (Steps 1-1B)
104
+ |- Check module-inventory.json (prerequisite from /fluent-module-validate)
105
+ |- Discover repo roots (Step 1) — classify each root
106
+ |- Read reference module metadata directly from module.json (no decompile)
107
+ |- Decompile standalone JARs only (Step 1A)
108
+ +- Validate workflow context (Step 1B)
109
+
110
+ Phase 2: Metadata Extraction (Steps 2-2A)
111
+ |- Build code map (Step 2) — for custom_extension roots only
112
+ |- Extract module identity (Step 2A) — version, symbolicName, Maven coords
113
+ +- Query live installed rules (MCP plugin.list) -> installed-rules.json
114
+
115
+ Phase 3: Mapping & Analysis (Steps 3-5)
116
+ |- source-map.json <- Step 2 output, foundation for everything
117
+ |- workflow-rule-map.json <- Step 3, needs source-map + installed-rules + workflows
118
+ |- constraints.json <- Step 5 input, needs source-map
119
+ |- behavior-map.md <- Step 4, needs source-map + workflow-rule-map
120
+ +- extension-plan.md <- Step 5, needs all above
121
+
122
+ Phase 4: Caching (Step 6)
123
+ +- fingerprint.json <- source input hash + artifact timestamps
124
+ ```
125
+
126
+ Dependency graph:
127
+ ```
128
+ module-inventory.json downloaded workflows
129
+ | |
130
+ source-map.json <---- installed-rules.json
131
+ | \ |
132
+ constraints.json workflow-rule-map.json
133
+ |
134
+ behavior-map.md
135
+ |
136
+ extension-plan.md
137
+ ```
138
+
139
+ ## Analysis Workflow
140
+
141
+ ### Step 1: Discover repository roots (recursive, no assumptions)
142
+
143
+ Under `accounts/<PROFILE>/SOURCE/`, recursively detect candidate module/repo roots by scanning for any of:
144
+
145
+ - `module.json`
146
+ - `pom.xml`
147
+ - `build.gradle` / `build.gradle.kts`
148
+ - `settings.gradle` / `settings.gradle.kts`
149
+ - `src/main/java/`
150
+ - `*.jar` / `*.zip` module artifacts
151
+ - rule markers (`@RuleInfo`, `extends BaseRule`, `ContextWrapper`)
152
+
153
+ If standard files are missing, continue with marker-based discovery instead of stopping.
154
+
155
+ **Handle double-nested git clone directories:**
156
+ A common pattern is `<repo-name>/<repo-name>/` where git clone creates a wrapper dir. If a directory under SOURCE contains only one subdirectory with a similar name and no direct module markers (no `pom.xml`, `module.json`, or `src/` at the outer level), treat the inner directory as the actual module root. Record `"doubleNested": true` in the source map.
157
+
158
+ **Classify each discovered root by type:**
159
+
160
+ | Classification | Indicators | Editable? | Buildable? |
161
+ |---------------|-----------|-----------|-----------|
162
+ | `custom_extension` | Has `src/main/java/`, `pom.xml`, rules in `module.json` | Yes | Yes (Maven) |
163
+ | `configuration_only` | Has `module.json` with empty `rules[]`, no `pom.xml`, no Java source | Yes (JSON) | No |
164
+ | `reference_artifact` | Has `module.json` + JAR under `assets/rules/`, no `src/main/java/` | No (read-only) | No |
165
+ | `standalone_jar` | Has `.jar`/`.zip` only, no `module.json` alongside | No (read-only) | No |
166
+
167
+ This classification drives downstream decisions: only `custom_extension` modules get full source analysis; `reference_artifact` modules get metadata directly from `module.json` without decompilation; `configuration_only` modules skip rule analysis entirely.
168
+
169
+ ### Step 1A: Decompile artifacts found under SOURCE
170
+
171
+ **Pre-check before decompiling:** For each JAR/ZIP artifact, check if a `module.json` exists alongside or inside it (reference module pattern with `assets/rules/` structure). If `module.json` is present, read rule metadata from it directly — decompilation is only needed for understanding rule implementation logic, not for metadata extraction. Mark these as `reference_artifact`.
172
+
173
+ **Locate JARs comprehensively:** Reference modules place JARs in multiple locations:
174
+ - Custom extension dist/: `SOURCE/<repo>/dist/*.jar`
175
+ - Reference module assets: `SOURCE/<module-name>/assets/rules/*.jar`
176
+ - Build intermediates: `SOURCE/<repo>/plugins/rules/*/target/*.jar`
177
+ - Standalone: `SOURCE/<module>.jar`
178
+
179
+ Use the Glob tool with pattern `accounts/<PROFILE>/SOURCE/**/*.jar` instead of shell `find` for cross-platform compatibility. Exclude `target/dependency/`, `.git/`, and `node_modules/` paths from results.
180
+
181
+ ```bash
182
+ find accounts/<PROFILE>/SOURCE/ -name "*.jar" \
183
+ -not -path "*/target/dependency/*" \
184
+ -not -path "*/.git/*" \
185
+ -not -path "*/node_modules/*" 2>/dev/null
186
+ ```
187
+
188
+ ```powershell
189
+ # PowerShell
190
+ Get-ChildItem "accounts\<PROFILE>\SOURCE" -Recurse -Filter "*.jar" -ErrorAction SilentlyContinue |
191
+ Where-Object { $_.FullName -notlike "*\target\dependency\*" -and $_.FullName -notlike "*\.git\*" -and $_.FullName -notlike "*\node_modules\*" }
192
+ ```
193
+
194
+ If JAR/ZIP artifacts are already present under `accounts/<PROFILE>/SOURCE/`, do not wait for additional inputs:
195
+
196
+ 1. Create a deterministic workspace:
197
+ - `accounts/<PROFILE>/SOURCE/.decompiled/<artifact-name>/`
198
+ 2. For `.zip` module artifacts, extract first and locate nested `.jar`/`.class` payloads before decompiling.
199
+ 3. Decompile into that folder (target classes first, then expand only if needed).
200
+ 4. Write a marker file `DECOMPILED.md` with:
201
+ - source artifact path
202
+ - decompiler used
203
+ - generated timestamp
204
+ - caveats (synthetic names, missing comments/generics)
205
+ 5. Treat decompiled output as analysis input alongside normal source trees.
206
+ 6. Mark evidence as `confirmed by decompile` in mappings/notes.
207
+ 7. Do not edit JAR/ZIP or decompiled output; treat both as read-only evidence.
208
+
209
+ Example commands:
210
+
211
+ > **Cross-platform note:** The decompile commands below assume a Unix-like shell (bash, Git Bash, WSL). On Windows without bash, use the PowerShell equivalents shown after each block. Alternatively, use the built-in Glob/Grep/Read tools for file discovery and content inspection.
212
+
213
+ **Auto-download CFR if not present:**
214
+ ```bash
215
+ # CFR is a single-JAR decompiler (~2MB), no installation needed
216
+ if [ ! -f tools/cfr.jar ]; then
217
+ mkdir -p tools
218
+ curl -L -o tools/cfr.jar "https://github.com/leibnitz27/cfr/releases/download/0.152/cfr-0.152.jar"
219
+ fi
220
+ ```
221
+
222
+ ```bash
223
+ mkdir -p accounts/<PROFILE>/SOURCE/.decompiled/<artifact-name>/
224
+
225
+ # Jar class listing (instant, reads ZIP index only — no decompilation)
226
+ jar tf accounts/<PROFILE>/SOURCE/<artifact>.jar
227
+
228
+ # Preferred decompile: CFR with --jarfilter to extract only rule classes
229
+ java -jar tools/cfr.jar "accounts/<PROFILE>/SOURCE/<artifact>.jar" \
230
+ --outputdir "accounts/<PROFILE>/SOURCE/.decompiled/<artifact-name>" \
231
+ --jarfilter "com.fluentcommerce.rule"
232
+
233
+ # Zip module extraction
234
+ unzip -o accounts/<PROFILE>/SOURCE/<artifact>.zip -d accounts/<PROFILE>/SOURCE/.decompiled/<artifact-name>/raw/
235
+ ```
236
+
237
+ The `--jarfilter` flag restricts decompilation to classes matching the package prefix, keeping output focused on rule logic only. Omit `--jarfilter` to decompile all classes.
238
+
239
+ ```powershell
240
+ # PowerShell — auto-download CFR
241
+ if (-not (Test-Path "tools\cfr.jar")) {
242
+ New-Item -ItemType Directory -Force -Path "tools"
243
+ Invoke-WebRequest -Uri "https://github.com/leibnitz27/cfr/releases/download/0.152/cfr-0.152.jar" -OutFile "tools\cfr.jar"
244
+ }
245
+
246
+ New-Item -ItemType Directory -Force -Path "accounts\<PROFILE>\SOURCE\.decompiled\<artifact-name>"
247
+
248
+ # Jar class listing
249
+ jar tf "accounts\<PROFILE>\SOURCE\<artifact>.jar"
250
+
251
+ # Preferred decompile: CFR with --jarfilter
252
+ java -jar tools/cfr.jar "accounts\<PROFILE>\SOURCE\<artifact>.jar" --outputdir "accounts\<PROFILE>\SOURCE\.decompiled\<artifact-name>" --jarfilter "com.fluentcommerce.rule"
253
+
254
+ # Zip module extraction
255
+ Expand-Archive -Path "accounts\<PROFILE>\SOURCE\<artifact>.zip" -DestinationPath "accounts\<PROFILE>\SOURCE\.decompiled\<artifact-name>\raw" -Force
256
+ ```
257
+
258
+ If no decompiler is available, extract metadata without full decompilation using JDK tools:
259
+
260
+ ```bash
261
+ # Extract manifest to discover registered rule names
262
+ jar xf <artifact>.jar META-INF/MANIFEST.MF
263
+ grep -A5 "Rubix-Rules" META-INF/MANIFEST.MF
264
+
265
+ # Disassemble specific classes for method signatures and annotations
266
+ javap -p "com/fluentcommerce/rule/SomeRule.class"
267
+ ```
268
+
269
+ ```powershell
270
+ # PowerShell
271
+ jar xf <artifact>.jar META-INF/MANIFEST.MF
272
+ Select-String -Path "META-INF\MANIFEST.MF" -Pattern "Rubix-Rules" -Context 0,5
273
+
274
+ javap -p "com/fluentcommerce/rule/SomeRule.class"
275
+ ```
276
+
277
+ This gives rule names and method signatures without a third-party decompiler. Continue with workflow-only + metadata analysis if even this is not possible (do not block the full run).
278
+
279
+ ### Step 1B: Validate workflow context before mapping
280
+
281
+ Before mapping workflow rules, validate `accounts/<PROFILE>/workflows/<RETAILER_REF>/workflow-context.json`:
282
+
283
+ - `profile` must match `<PROFILE>`
284
+ - `retailerRef` (or `retailer`) must match `<RETAILER_REF>`
285
+ - workflow file count should be non-zero for a full mapping run
286
+
287
+ If context is missing or mismatched, recreate it and flag confidence as reduced until workflows are refreshed.
288
+
289
+ ### Step 2: Build a Code Map
290
+
291
+ Create a compact map with:
292
+
293
+ - Repo/module root
294
+ - Build system (Maven/Gradle/unknown)
295
+ - Module identity (`symbolicName`, `version`, and extraction source)
296
+ - Rule classes discovered
297
+ - Shared utils/services
298
+ - Suspected entry points and side-effect points
299
+
300
+ Minimum output table:
301
+
302
+ | Repo | Root | Classification | Build | Rule markers | Notes |
303
+ |---|---|---|---|---|---|
304
+
305
+ ### Step 2A: Module identity extraction (version + symbolic name)
306
+
307
+ Capture both `symbolicName` and `version` per module using this precedence:
308
+
309
+ `symbolicName`:
310
+ 1. `resources/module.json` -> `name` (preferred)
311
+ 2. JAR `META-INF/MANIFEST.MF` -> `Bundle-SymbolicName` (if present)
312
+ 3. POM fallback -> `<groupId>/<artifactId>` (or `<artifactId>` if `groupId` missing)
313
+
314
+ `version`:
315
+ 1. `resources/module.json` -> `version` (preferred)
316
+ 2. POM -> `<project><version>` (fallback to `<project><parent><version>` if module version omitted)
317
+ 3. JAR manifest -> `Implementation-Version` or `Bundle-Version`
318
+
319
+ Always store where values came from (for traceability), for example `versionSource: "module.json"` or `versionSource: "pom.parent.version"`.
320
+
321
+ **Maven multi-module version resolution:**
322
+ Many custom modules use a parent/child POM pattern:
323
+ ```
324
+ plugins/pom.xml (parent, defines version)
325
+ plugins/types/<name>/pom.xml (child, inherits version)
326
+ plugins/util/<name>/pom.xml (child, inherits version)
327
+ plugins/rules/<name>/pom.xml (child, inherits version)
328
+ ```
329
+
330
+ Version extraction algorithm:
331
+ 1. Read `plugins/pom.xml` -> `<project><version>` (parent version, source of truth)
332
+ 2. If parent has no `<version>`, read `<parent><version>` from parent's parent
333
+ 3. For any child POM with no `<version>`: read `<parent><version>` reference
334
+ 4. Record inheritance depth: `"pom.project.version"` vs `"pom.parent.version"`
335
+
336
+ ### Step 3: Map workflow rules to source classes
337
+
338
+ From workflow JSON(s), collect rule names and map to discovered classes.
339
+
340
+ For each mapped rule, extract:
341
+
342
+ - expected props/inputs
343
+ - query/mutation/event calls
344
+ - status changes
345
+ - branch conditions and guards
346
+
347
+ ### Step 4: Explain behavior with confidence labels
348
+
349
+ For each important behavior, report:
350
+
351
+ - trigger (event/status/user action)
352
+ - processing path (ruleset -> class -> key methods)
353
+ - side effects (state/event/attributes/external calls)
354
+ - confidence:
355
+ - **confirmed by source**
356
+ - **inferred from workflow metadata**
357
+ - **inferred from runtime evidence**
358
+
359
+ ### Step 5: Extension readiness analysis
360
+
361
+ Return extension options with risk:
362
+
363
+ 1. Add a new ruleset + existing rule reuse
364
+ 2. Add a new rule class (recommended for isolated behavior)
365
+ 3. Modify existing rule (higher regression risk)
366
+
367
+ For each option include:
368
+
369
+ - changed files
370
+ - test impact
371
+ - deployment impact
372
+ - rollback path
373
+
374
+ ### Step 6: Write or refresh analysis artifacts
375
+
376
+ At the end of every run, write or refresh the full artifact bundle (or the incremental subset when freshness rules allow):
377
+
378
+ - `accounts/<PROFILE>/analysis/custom-code/source-map.json`
379
+ - `accounts/<PROFILE>/analysis/custom-code/workflow-rule-map.json`
380
+ - `accounts/<PROFILE>/analysis/custom-code/constraints.json`
381
+ - `accounts/<PROFILE>/analysis/custom-code/behavior-map.md`
382
+ - `accounts/<PROFILE>/analysis/custom-code/extension-plan.md`
383
+ - `accounts/<PROFILE>/analysis/custom-code/fingerprint.json`
384
+
385
+ Also persist installed rule evidence:
386
+
387
+ - `accounts/<PROFILE>/analysis/installed-rules.json`
388
+
389
+ If any required file cannot be generated, record the blocker and leave explicit TODO notes in `constraints.json` under `missingSources`/`risks`.
390
+
391
+ ## Handling Non-Standard Structures
392
+
393
+ Do not require strict Fluent module conventions.
394
+
395
+ If structure is non-standard:
396
+
397
+ 1. Use semantic markers (annotations, base classes, utility calls) to locate logic.
398
+ 2. Infer module boundaries from package names and build files.
399
+ 3. Validate assumptions against workflow bindings and runtime event evidence.
400
+ 4. Call out unknowns explicitly instead of guessing.
401
+
402
+ ## Escalation Path
403
+
404
+ If source is incomplete or unavailable:
405
+
406
+ 1. Check for existing JAR/ZIP under `accounts/<PROFILE>/SOURCE/` and decompile first.
407
+ 2. Ask for missing repos under `accounts/<PROFILE>/SOURCE/` if neither source nor artifacts exist.
408
+ 3. Request module ZIP/JAR if still missing.
409
+ 4. Decompile only target classes tied to mapped rules.
410
+ 5. Re-run mapping and confidence labels.
411
+ 6. For implementation requests, recommend source-level change options and ask for source repo onboarding when only artifacts are present.
412
+
413
+ ## Reusable Artifact Contract
414
+
415
+ Always write analysis artifacts to:
416
+
417
+ `accounts/<PROFILE>/analysis/custom-code/`
418
+
419
+ Required files:
420
+
421
+ 1. `source-map.json`
422
+ - Repo/module roots discovered
423
+ - Build system
424
+ - Rule classes and marker evidence
425
+ 2. `workflow-rule-map.json`
426
+ - Workflow ruleset/rule names mapped to source classes
427
+ - Match confidence (`exact`, `probable`, `unresolved`)
428
+ 3. `constraints.json`
429
+ - Non-standard structure notes
430
+ - Missing sources/artifacts
431
+ - Known extension constraints and risks
432
+ 4. `behavior-map.md`
433
+ - Human-readable behavior flow with evidence labels
434
+ 5. `extension-plan.md`
435
+ - Recommended extension option, file-level changes, tests, deploy/rollback notes
436
+ 6. `fingerprint.json`
437
+ - Input hashes/fingerprints for change detection
438
+ - Freshness decision (`reuse` vs `regenerate`)
439
+
440
+ Required metadata in each JSON file:
441
+
442
+ - `profile`
443
+ - `generatedAt` (ISO timestamp)
444
+ - `objective`
445
+ - `sourceInputHash`
446
+ - `contentHash`
447
+ - `confidenceSummary`
448
+ - `inputFingerprint`
449
+
450
+ For markdown artifacts (`behavior-map.md`, `extension-plan.md`), include a short header block with at least:
451
+
452
+ - `profile`
453
+ - `generatedAt`
454
+ - `sourceInputHash`
455
+
456
+ ### Artifact generation gate (must pass before completion)
457
+
458
+ Do not mark analysis as complete until all checks pass:
459
+
460
+ 1. All six required artifacts exist in `accounts/<PROFILE>/analysis/custom-code/`.
461
+ 2. `source-map.json`, `workflow-rule-map.json`, `constraints.json`, and `fingerprint.json` include `sourceInputHash` + `contentHash`.
462
+ 3. `workflow-rule-map.json` mappings use `source` (`custom` | `reference` | `unresolved`) and avoid legacy `unmapped` buckets.
463
+ 4. If decompiled evidence is used, impacted mappings include confidence text that indicates decompile-derived evidence.
464
+ 5. `accounts/<PROFILE>/analysis/installed-rules.json` exists (from MCP `plugin.list`, or a documented fallback snapshot if MCP is unavailable).
465
+
466
+ ### freshness model
467
+
468
+ Use this decision before re-parsing:
469
+
470
+ 1. Build `inputFingerprint` from source/workflow inputs (paths + checksums/hashes or deterministic counts).
471
+ 2. Compare with `fingerprint.json` from the last run.
472
+ 3. If unchanged and objective is compatible, reuse existing artifacts.
473
+ 4. If changed (or objective differs), regenerate all artifacts and overwrite fingerprints.
474
+
475
+ ### incremental refresh (default)
476
+
477
+ Do not regenerate everything for every change. Refresh only what changed:
478
+
479
+ | Change detected | Refresh scope |
480
+ |---|---|
481
+ | One or few `src/main/java` rule files changed | Update affected rule entries in `source-map.json`, then recompute only impacted mappings in `workflow-rule-map.json`, plus related risks in `constraints.json` |
482
+ | Only tests changed | Update `hasTest`/test metadata in `source-map.json` and any test-related risk notes in `constraints.json` |
483
+ | Only workflow JSON changed | Refresh `workflow-rule-map.json` + `behavior-map.md`; keep source map if source fingerprint unchanged |
484
+ | `module.json` changed | Refresh `source-map.json` + `workflow-rule-map.json` + `constraints.json` |
485
+ | Folder structure moved/large rename | Full regenerate of all artifacts |
486
+
487
+ Full regenerate is fallback, not default.
488
+
489
+ ### source-map.json schema
490
+
491
+ ```json
492
+ {
493
+ "profile": "<PROFILE>",
494
+ "generatedAt": "2026-02-22T10:00:00Z",
495
+ "objective": "full analysis",
496
+ "sourceInputHash": "f8e7d6c5b4a39281",
497
+ "contentHash": "a1b2c3d4e5f6a7b8",
498
+ "confidenceSummary": {
499
+ "exact": 10,
500
+ "probable": 2,
501
+ "unresolved": 0
502
+ },
503
+ "inputFingerprint": {
504
+ "moduleJsonCount": 2,
505
+ "javaFileCount": 48,
506
+ "workflowJsonCount": 17
507
+ },
508
+ "modules": [
509
+ {
510
+ "name": "fc-module-custom-extension",
511
+ "classification": "custom_extension",
512
+ "isEditable": true,
513
+ "isBuildable": true,
514
+ "doubleNested": false,
515
+ "symbolicName": "fluent-commerce/fc-module-custom-extension",
516
+ "version": "0.0.29",
517
+ "versionSource": "module.json",
518
+ "identitySource": "module.json",
519
+ "osgiSymbolicName": "_.hmextensions",
520
+ "artifactCoordinates": {
521
+ "groupId": "com.fluentcommerce",
522
+ "artifactId": "fc-module-custom-extension",
523
+ "version": "0.0.29"
524
+ },
525
+ "repoPath": "accounts/<PROFILE>/SOURCE/fluentcommerce-fc-module-custom-extension",
526
+ "moduleJsonPath": "resources/module.json",
527
+ "pomPath": "plugins/pom.xml",
528
+ "manifestPath": "META-INF/MANIFEST.MF",
529
+ "buildSystem": "maven",
530
+ "buildRoot": "plugins/",
531
+ "buildCommand": "cd plugins && mvn clean install",
532
+ "packageScript": "scripts/build-module.sh",
533
+ "outputArtifact": "dist/<name>-<version>.zip",
534
+ "dependencies": [
535
+ { "name": "fc-module-core", "type": "fluent", "version": "1.0.0" }
536
+ ],
537
+ "compatibility": {
538
+ "minRubixVersion": "2.0.0",
539
+ "rubixPluginSdk": "2.0.0"
540
+ },
541
+ "patterns": {
542
+ "basePackage": "com.fluentcommerce.rule",
543
+ "subPackages": ["common", "fulfilment", "order", "returnorder", "variantproduct"],
544
+ "baseClass": "BaseRule",
545
+ "contextWrapper": "ContextWrapper",
546
+ "testFramework": "JUnit 5 + Mockito",
547
+ "testMirror": "src/test/java/ mirrors src/main/java/"
548
+ },
549
+ "rules": [
550
+ {
551
+ "name": "SendWebhookWithDynamicAttributes",
552
+ "class": "com.fluentcommerce.rule.common.SendWebhookWithDynamicAttributes",
553
+ "classPath": "plugins/rules/.../SendWebhookWithDynamicAttributes.java",
554
+ "description": "Send webhooks with dynamically built attributes",
555
+ "parameters": [
556
+ { "name": "setting", "type": "String", "description": "Setting ref for webhook config" }
557
+ ],
558
+ "entityTypes": ["ORDER", "FULFILMENT"],
559
+ "graphqlUsage": [],
560
+ "sendsEvents": false,
561
+ "setsState": false,
562
+ "readsSettings": true,
563
+ "hasTest": true,
564
+ "testPath": "plugins/rules/.../SendWebhookWithDynamicAttributesTest.java",
565
+ "testCount": 5
566
+ }
567
+ ],
568
+ "graphqlFiles": [
569
+ { "path": "src/main/resources/graphql/orderQuery.graphql", "type": "query", "usedByRules": ["CreateMissingProductVariant"] }
570
+ ],
571
+ "retailerConfigs": [
572
+ { "file": "module.config.<RETAILER_REF>.fc-module-custom-extension.json", "retailer": "<RETAILER_REF>" }
573
+ ]
574
+ }
575
+ ],
576
+ "summary": {
577
+ "totalModules": 2,
578
+ "codeModules": 1,
579
+ "configOnlyModules": 1,
580
+ "referenceModuleArtifacts": 4,
581
+ "totalRules": 12,
582
+ "rulesWithTests": 8,
583
+ "rulesWithoutTests": 4,
584
+ "testCoveragePercent": 67,
585
+ "settingsFiles": 28,
586
+ "workflowFragments": 4
587
+ }
588
+ }
589
+ ```
590
+
591
+ ### workflow-rule-map.json schema
592
+
593
+ ```json
594
+ {
595
+ "profile": "<PROFILE>",
596
+ "generatedAt": "2026-02-22T10:00:00Z",
597
+ "objective": "workflow to rule mapping",
598
+ "sourceInputHash": "f8e7d6c5b4a39281",
599
+ "contentHash": "99aa88bb77cc66dd",
600
+ "confidenceSummary": {
601
+ "exact": 22,
602
+ "probable": 41,
603
+ "unresolved": 3
604
+ },
605
+ "inputFingerprint": {
606
+ "workflowJsonCount": 17,
607
+ "ruleInvocationCount": 66
608
+ },
609
+ "mappings": [
610
+ {
611
+ "workflow": "ORDER::HD",
612
+ "ruleset": "OnOrderComplete",
613
+ "ruleName": "<ACCOUNT>.custom-extension.SendWebhookWithDynamicAttributes",
614
+ "source": "custom",
615
+ "sourceClass": "com.fluentcommerce.rule.common.SendWebhookWithDynamicAttributes",
616
+ "classPath": "plugins/rules/.../SendWebhookWithDynamicAttributes.java",
617
+ "confidence": "exact",
618
+ "props": {
619
+ "setting": "webhook.order.complete"
620
+ }
621
+ },
622
+ {
623
+ "workflow": "ORDER::HD",
624
+ "ruleset": "OnOrderCreated",
625
+ "ruleName": "<ACCOUNT>.core.SetState",
626
+ "source": "reference",
627
+ "referenceModule": "core",
628
+ "confidence": "probable",
629
+ "props": {
630
+ "status": "RECEIVED"
631
+ }
632
+ },
633
+ {
634
+ "workflow": "ORDER::HD",
635
+ "ruleset": "UnexpectedRuleset",
636
+ "ruleName": "<ACCOUNT>.custom.UnknownRule",
637
+ "source": "unresolved",
638
+ "reason": "Not found in custom source, installed-rules snapshot, or reference catalog",
639
+ "confidence": "unresolved"
640
+ }
641
+ ]
642
+ }
643
+ ```
644
+
645
+ ### constraints.json schema
646
+
647
+ ```json
648
+ {
649
+ "profile": "<PROFILE>",
650
+ "generatedAt": "2026-02-22T10:00:00Z",
651
+ "objective": "extend webhook logic",
652
+ "sourceInputHash": "f8e7d6c5b4a39281",
653
+ "contentHash": "11223344aabbccdd",
654
+ "confidenceSummary": {
655
+ "exact": 22,
656
+ "probable": 41,
657
+ "unresolved": 3
658
+ },
659
+ "inputFingerprint": {
660
+ "moduleJsonCount": 2,
661
+ "javaFileCount": 48,
662
+ "workflowJsonCount": 17
663
+ },
664
+ "structure": {
665
+ "isStandard": true,
666
+ "deviations": []
667
+ },
668
+ "missingSources": [],
669
+ "missingTests": ["CreateMissingProductVariant"],
670
+ "extensionConstraints": [
671
+ {
672
+ "constraint": "BaseRule required",
673
+ "detail": "All rules must extend BaseRule, not Rule directly",
674
+ "impact": "new rules"
675
+ }
676
+ ],
677
+ "risks": [
678
+ {
679
+ "area": "webhook rule modification",
680
+ "risk": "medium",
681
+ "riskSeverity": "medium",
682
+ "mitigation": "Add integration tests across ORDER and FULFILMENT flows before deploy",
683
+ "reason": "Used in 3 workflows across ORDER and FULFILMENT entities"
684
+ }
685
+ ]
686
+ }
687
+ ```
688
+
689
+ ### fingerprint.json schema
690
+
691
+ ```json
692
+ {
693
+ "profile": "<PROFILE>",
694
+ "generatedAt": "2026-02-22T10:00:00Z",
695
+ "objective": "full analysis",
696
+ "freshnessDecision": "regenerate",
697
+ "sourceInputHash": "f8e7d6c5b4a39281",
698
+ "contentHash": "ddee1122ccbb3344",
699
+ "lastRegeneratedAt": "2026-02-22T10:00:00Z",
700
+ "inputFingerprint": {
701
+ "moduleJsonCount": 2,
702
+ "javaFileCount": 48,
703
+ "workflowJsonCount": 17
704
+ },
705
+ "incrementalRefreshMatrix": {
706
+ "javaRuleChange": "refresh source-map + impacted workflow mappings + related constraints",
707
+ "testsOnly": "refresh test metadata and test-risk notes",
708
+ "workflowJsonChange": "refresh workflow-rule-map + behavior-map",
709
+ "moduleJsonChange": "refresh source-map + workflow-rule-map + constraints",
710
+ "structureMove": "full regenerate"
711
+ },
712
+ "incrementalScope": {
713
+ "sourceMapStale": true,
714
+ "workflowRuleMapStale": true,
715
+ "constraintsStale": true,
716
+ "behaviorMapStale": true,
717
+ "extensionPlanStale": true
718
+ }
719
+ }
720
+ ```
721
+
722
+ ### markdown artifact header template
723
+
724
+ Use this header block at the top of both `behavior-map.md` and `extension-plan.md`:
725
+
726
+ ```markdown
727
+ # <Artifact Title>
728
+
729
+ Generated at: <ISO-8601>
730
+ Profile: <PROFILE>
731
+ Source input hash: <sourceInputHash>
732
+ ```
733
+
734
+ ## Reference Module Integration
735
+
736
+ ### Rule naming pattern
737
+
738
+ Fluent Commerce rules follow the pattern `<ACCOUNT>.<MODULE>.<RuleName>`:
739
+ - `FLUENTRETAIL.base.*` — Platform-standard rules (always available)
740
+ - `FLUENTRETAIL.globalinventory.*` — Platform inventory rules (always available)
741
+ - `<ACCOUNT>.order.*` — Order module rules installed on the account
742
+ - `<ACCOUNT>.core.*` — Core module rules installed on the account
743
+ - `<ACCOUNT>.custom-extension.*` — Custom module rules
744
+
745
+ ### Pre-fed reference catalog
746
+
747
+ A static catalog of platform-standard (`FLUENTRETAIL.*`) rules ships at:
748
+
749
+ ```
750
+ fluent-ai-skills/content/dev/reference-modules/catalog.json
751
+ ```
752
+
753
+ This contains 232 rules with full metadata (description, parameters, entity types, produced events). Use this for offline analysis or when MCP tools are unavailable.
754
+
755
+ ### Live installed rules snapshot
756
+
757
+ During analysis, query `plugin.list` via MCP to get all rules installed on the account:
758
+
759
+ ```
760
+ MCP: plugin.list (no filter)
761
+ ```
762
+
763
+ Save the output as:
764
+
765
+ ```
766
+ accounts/<PROFILE>/analysis/installed-rules.json
767
+ ```
768
+
769
+ This captures both reference AND custom rules specific to the account, with the account prefix.
770
+
771
+ **Important:** Verify that MCP is connected to the same account as the analysis profile (see Pre-Check). If MCP points at a different account, the `plugin.list` results will have the wrong `<ACCOUNT>` prefix and must NOT be saved for this profile.
772
+
773
+ If MCP is unavailable or connected to a different account, write a fallback snapshot with `"source": "workflow-observed-fallback"` built from all rule names observed in workflow JSONs, and flag reduced confidence in `constraints.json`.
774
+
775
+ ### Rule resolution order
776
+
777
+ When resolving a rule name from a workflow:
778
+
779
+ 1. **Custom source** — check `source-map.json` → `modules[].rules[]` (has source code)
780
+ 2. **Installed rules** — check `installed-rules.json` (has metadata from plugin.list)
781
+ 3. **Reference catalog** — check `reference-modules/catalog.json` (offline fallback)
782
+ 4. **Unresolved** — mark as unknown, flag for investigation
783
+
784
+ ### workflow-rule-map.json: source field
785
+
786
+ Every mapping must include a `source` field:
787
+
788
+ ```json
789
+ {
790
+ "ruleName": "<ACCOUNT>.custom-extension.SendWebhookWithDynamicAttributes",
791
+ "source": "custom",
792
+ "sourceClass": "com.fluentcommerce.rule.common.SendWebhookWithDynamicAttributes"
793
+ }
794
+ ```
795
+
796
+ ```json
797
+ {
798
+ "ruleName": "<ACCOUNT>.core.SetState",
799
+ "source": "reference",
800
+ "referenceModule": "base",
801
+ "description": "Sets entity status to specified value",
802
+ "parameters": [{ "name": "status", "type": "STRING" }]
803
+ }
804
+ ```
805
+
806
+ ```json
807
+ {
808
+ "ruleName": "<ACCOUNT>.custom.UnknownRule",
809
+ "source": "unresolved",
810
+ "reason": "Not found in custom source, installed rules, or reference catalog"
811
+ }
812
+ ```
813
+
814
+ This eliminates the "unmapped" category — every rule is resolved or explicitly unresolved.
815
+
816
+ ## Content Hash and Change Detection
817
+
818
+ ### Staleness check
819
+
820
+ Every JSON artifact includes a `contentHash` field — a SHA-256 hash of the source inputs used to generate it:
821
+
822
+ ```json
823
+ {
824
+ "profile": "<PROFILE>",
825
+ "generatedAt": "2026-02-22T10:00:00Z",
826
+ "contentHash": "a1b2c3d4e5f6g7h8",
827
+ "sourceInputHash": "f8e7d6c5b4a39281"
828
+ }
829
+ ```
830
+
831
+ - `contentHash` — hash of the artifact content itself
832
+ - `sourceInputHash` — hash of the source files used to generate it
833
+
834
+ ### Computing source input hash
835
+
836
+ Hash these inputs together (SHA-256, first 16 hex chars):
837
+
838
+ 1. All `module.json` files under `accounts/<PROFILE>/SOURCE/` (content)
839
+ 2. All `*.java` files under `accounts/<PROFILE>/SOURCE/` (file paths + sizes, NOT full content — for speed)
840
+ 3. All workflow JSON files under `accounts/<PROFILE>/workflows/<RETAILER_REF>/` (content)
841
+
842
+ ### Skip/refresh logic
843
+
844
+ ```
845
+ On invocation:
846
+ 1. Compute current sourceInputHash from source files
847
+ 2. Read existing source-map.json (if present)
848
+ 3. Compare sourceInputHash values
849
+ ├── Same → artifacts are fresh, skip analysis (print "No changes detected")
850
+ └── Different → source has changed, re-analyze
851
+ 4. --refresh flag → always re-analyze regardless of hash
852
+ 5. --module <name> → re-analyze only that module
853
+ ```
854
+
855
+ ### Hash computation pseudo-code
856
+
857
+ ```
858
+ inputs = []
859
+ for each module.json in accounts/<PROFILE>/SOURCE/**/:
860
+ inputs.append(file_content)
861
+ for each *.java in accounts/<PROFILE>/SOURCE/**/:
862
+ inputs.append(file_path + ":" + file_size)
863
+ for each *.json in accounts/<PROFILE>/workflows/<RETAILER_REF>/:
864
+ inputs.append(file_content)
865
+ sourceInputHash = sha256(sort(inputs).join("\n"))[:16]
866
+ ```
867
+
868
+ Using file paths + sizes for Java files (instead of full content) keeps the hash fast for large codebases while still detecting new/deleted/renamed files. Full content hashing of module.json and workflows is fine because those files are small.
869
+
870
+ ## Cross-Skill Reuse Rules
871
+
872
+ Other skills should consume these artifacts before re-scanning:
873
+
874
+ - `/fluent-workflow-builder`: reuse `workflow-rule-map.json` + `constraints.json`
875
+ - `/fluent-rule-scaffold`: reuse `source-map.json` + `extension-plan.md`
876
+ - `/fluent-trace`: reuse `behavior-map.md` + `workflow-rule-map.json`
877
+ - `/fluent-e2e-test`: reuse `constraints.json` for scenario boundaries
878
+ - `/fluent-workflow-analyzer`: reuse `source-map.json` for rule annotations
879
+
880
+ Reference module knowledge is also available to all skills:
881
+
882
+ - `reference-modules/catalog.json` — offline rule lookup (232 FLUENTRETAIL rules)
883
+ - `installed-rules.json` — live snapshot of all rules on the account
884
+
885
+ If artifacts are stale (hash mismatch) or objective changed, regenerate and keep the same file names.
886
+
887
+ ## Output Template
888
+
889
+ Use this structure:
890
+
891
+ 1. **Source map** (repos/modules/rules found)
892
+ 2. **Installed rules** (from plugin.list, reference + custom)
893
+ 3. **Behavior map** (what code does, with evidence)
894
+ 4. **Extension plan** (recommended option + risks)
895
+ 5. **Open gaps** (missing sources/artifacts or ambiguous logic)