---
name: fluent-build
description: Build, version, package, and deploy Fluent Commerce extension modules. Handles Maven compilation, version bumping, module packaging, and deployment. Triggers on "build module", "bump version", "package module", "deploy module", "maven build".
user-invocable: true
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
argument-hint: [build|version|package|deploy|full] [--skip-tests]
cursor-tier: auto
planning-gate: advisory
---

# Build and Packaging

Build and package Fluent extension modules with consistent versioning.

## Pre-flight: Feedback Check

Before starting, check for past learnings from this skill:

1. Check if `accounts/<PROFILE>/feedback/fluent-build.jsonl` exists
2. If yes, read last 20 records
3. Filter to: FAILURE or USER_CORRECTED outcomes, confidence = CONFIRMED or PROMOTED
4. Extract top 3 relevant learnings — use as internal guidance during execution
5. Do NOT show raw feedback to the user — silently adjust approach based on past issues

## Planning Gate

### Pre-flight Chain (Three-Level)

Before version bumping or packaging, run the three-level pre-flight check:

1. **Spec check:** If `accounts/<PROFILE>/features/<slug>/status.json` exists for this work:
   - Check `spec: "APPROVED"` — If missing, BLOCK: `→ BLOCKED: PREREQ_MISSING — Run /fluent-use-case-discover first`
   - Check `plan: "APPROVED"` — If missing, BLOCK: `→ BLOCKED: PLAN_REQUIRED — Run /fluent-feature-plan first`
   - If both approved, skip to implementation referencing the plan's §17 (Deployment) section
2. **Multi-artifact work** (build + rules + workflows + settings): STOP. Invoke `/fluent-feature-plan` first — this skill cannot be used for multi-artifact work without a feature plan
3. **Standalone build-only work** (no feature context, no multi-artifact):
   - Check `accounts/<PROFILE>/tasks/` for a task plan with `Status: APPROVED`
   - If approved task plan found, skip to implementation
   - If no plan, continue to the Planning Gate below to write a plan for this skill
4. **Plain `mvn clean install` builds** (no version change) are always exempt from planning

**Before version bumping or packaging, write a plan using the template from `PLAN_TEMPLATE.md` in the `fluent-feature-plan` skill.** Plain `mvn clean install` builds (no version change) are exempt.

**Build-specific emphasis — ensure these are covered:**

1. **Business Context (Section 1)** — what change drives this version bump
2. **Scope (Section 2)** — current version → new version, bump type (patch/minor/major) with rationale
3. **Files (Section 6)** — all pom.xml files, module.json, CHANGELOG.md that will be modified
4. **Impacted retailers (Section 4.8)** — which environments get the new version
5. **Test Plan (Section 8)** — confirm tests pass before versioning
6. **Deployment Sequence (Section 9)** — build → test → version bump → package → deploy order

**Write the plan to:** `accounts/<PROFILE>/tasks/<YYYY-MM-DD>-build-<slug>.md`. Set `Status: PENDING`.

Present the full plan content to the user and wait for approval before bumping versions. On approval, update the file to `Status: APPROVED`. If the user says "just do it", proceed directly (still write the file for audit trail).

## Ownership Boundary

This skill owns:

- version bumping
- Maven build/test execution
- module ZIP packaging

This skill does **not** own deployment runbooks. For deployment:

- use `/fluent-module-deploy` for manual installs
- use `flow-run` for guarded automation and JSON run reporting

## Handoff Protocol

### Signals emitted by this skill

| Signal | Condition | Example |
|--------|-----------|---------|
| `-> READY: <path>` | Build successful, artifact produced | `-> READY: accounts/MY_PROFILE/SOURCE/backend/fc-module-my-extensions/dist/module-0.0.30.jar` |
| `-> NEXT: /fluent-<skill>` | Ready for pre-deploy check | `-> NEXT: /fluent-pre-deploy-check` |
| `-> BLOCKED: <reason>` | Build failed | `-> BLOCKED: VALIDATION_FAILED — Compilation error in CancelOrderRule.java:45` |

### Error codes

| Code | Condition | Recovery |
|------|-----------|----------|
| `PLAN_REQUIRED` | Version bump attempted without approved plan | Run `/fluent-feature-plan` first |
| `PREREQ_MISSING` | Module validation report missing or stale | Run `/fluent-module-validate` first |
| `VALIDATION_FAILED` | Compilation error or test failure | Fix code and re-run `/fluent-build` |

## When to Use

- Java rule or utility code changed
- Workflow JSON, settings, or resource files changed in `resources/`
- module version needs bumping before redeploy
- a new deployable ZIP artifact is required
- build errors need diagnosis and recovery

## Progress

Emit this block at each phase transition to show progress:

```
▸ /fluent-build [1/4]
  ✓ Module validation gate   → Version bump
  ○ Compile (mvn install)    ○ Package ZIP
```

Update the block as each phase completes — mark completed phases with `✓`, the active phase with `→`, and remaining phases with `○`. Replace `[1/4]` with the current phase number.

## Pre-Check: Module Validation (Enforced Gate)

Before building, check the cached validation report from `/fluent-module-validate`:

```
accounts/<PROFILE>/reports/module-validate/<module-name>.report.json
```

**This is a gating check, not advisory:**

1. **Report exists and `summary.status == "NEEDS_FIXES"`** -- **STOP**. List all FAIL items from the report. Ask the user to confirm proceeding despite validation failures. Do NOT silently continue.

2. **Report exists and `summary.status == "READY_FOR_BUILD"`** -- proceed with build.

3. **Report is missing or stale** (content hash in `.hash` file doesn't match current source) -- **run `/fluent-module-validate` inline** before building. This ensures validation is always current. If inline validation finds FAIL items, apply the same gating behavior as case 1.

The validation report checks: module.json structure, POM consistency, version alignment, rule wiring, test coverage, and more. Building a module that fails validation wastes time and may produce a broken artifact.

## Pre-Check: Load Source Analysis

Before building, check if `/fluent-custom-code` analysis artifacts exist:

```
accounts/<PROFILE>/analysis/code/source-map.json
```

If found, read to discover:
- `modules[].buildRoot` — correct directory to run Maven from
- `modules[].buildCommand` — build command
- `modules[].packageScript` — packaging script path
- `modules[].outputArtifact` — expected output ZIP
- `modules[].version` — current version (for bump validation)

If not found, fall back to the defaults below. Treat artifact-gate failures as "not found" (for example missing required files, missing hashes, or blocking `missingSources` in `constraints.json`).

## Prerequisites Check

Run before building:

```bash
node --version
java --version
mvn --version
fluent --version
```

Use the repository-supported runtime versions for your environment.

## 1) Version Bump (required before redeploy)

> **Full version lifecycle:** For version status, sync, CHANGELOG updates, and git tagging, use `/fluent-version-manage`. This section covers the minimum bump needed before a build.

### When to Bump

**A version bump is required whenever ANY content in the module changes — not just Java code.**

| Change Type | Examples | Bump Required? | Why |
|------------|---------|---------------|-----|
| Java code | New rule, bug fix, refactor | **YES** | JAR filename includes version; CLI skips upload if same version exists |
| Workflow JSON | New ruleset, status change, rule reorder | **YES** | Module version tracks what's deployed; without bump the module install looks identical to last deploy |
| Settings | New setting, value change | **YES** | Same reason — traceability of what version introduced the change |
| Resources | New assets, config templates | **YES** | Packaged into the module ZIP; version is the audit trail |
| No content change | Re-deploy same content | **NO** | Use `--force` flag if re-install is needed |

**Key gotcha:** The Fluent CLI checks the plugin JAR filename against what's already uploaded. If `fc-module-<name>-0.0.30.jar` is already active, uploading the same version results in `"already uploaded: Active - nothing more to do"` — the JAR is silently skipped. **Both `resources/module.json` AND all `pom.xml` files must be bumped in sync**, because Maven uses the POM version for the JAR filename while the CLI uses `module.json` version for the module-level check.

### Version Sync — All Files Must Match

Fluent ignores re-uploading the same module version. Keep these files in sync:

| File | Field |
|---|---|
| `plugins/pom.xml` | parent `<version>` |
| `plugins/rules/<module-alias>/pom.xml` | parent/module `<version>` |
| `plugins/types/<module-alias>/pom.xml` | parent/module `<version>` |
| `plugins/util/<module-alias>/pom.xml` | parent/module `<version>` |
| `resources/module.json` | `"version"` |

### Bump Procedure

1. Read current `resources/module.json` version.
2. Increment patch version (or minor/major per semver rationale).
3. Update `resources/module.json` version field.
4. Update all POM files — use Maven to ensure consistency:
   ```bash
   cd plugins/ && mvn versions:set -DnewVersion=<NEW_VERSION> -DgenerateBackupPoms=false
   ```
5. Verify old version no longer exists in the module source tree:
   ```bash
   grep -r "<old-version>" plugins/*/pom.xml resources/module.json
   ```

## 2) Build

### Pre-Build Version Check

Before running Maven, verify the version is deployable:

1. Read the current version from `pom.xml` (`<version>` tag) or `module.json` (`version` field).
2. Check deployed versions: run `fluent module list -p <PROFILE>` or `/fluent-version-manage status`.
3. If the current version **matches an already-deployed version**, WARN:
   > "Version X.Y.Z is already deployed. The Fluent CLI will silently skip the upload. Run `/fluent-version-manage bump` to increment the version first."
4. Only proceed after the user confirms ("build anyway") or bumps the version.

### Maven Execution

From `plugins/`:

```bash
# Full build
mvn clean install

# Build without tests
mvn clean install -DskipTests

# Build targeted module with dependencies
mvn clean install -pl rules/<module-alias> -am
```

### Post-Build Output Analysis

After Maven completes, parse the output for actionable signals:

1. **BUILD FAILURE**: If output contains `BUILD FAILURE`, extract the error message and report as a **blocking failure**. Do not proceed to packaging.
2. **Warnings**: Collect all `[WARNING]` lines. Report count and summary as non-blocking warnings.
3. **Test results**: Find the `Tests run:` summary line. Extract passed/failed/skipped/errors counts. If `Failures > 0` or `Errors > 0`, report as **blocking** -- tests must pass before deployment.
4. **Skipped tests**: If output contains `Tests are skipped` or `-DskipTests`, warn: "Tests were skipped. Run full test suite before deployment."
5. **Save structured result** to `accounts/<PROFILE>/reports/build/<MODULE>-<VERSION>.build-result.json`:
   ```json
   { "status": "SUCCESS|FAILED", "warnings": 0, "tests": { "passed": 0, "failed": 0, "skipped": 0, "errors": 0 }, "errors": [] }
   ```
   This file is consumed by `/fluent-pre-deploy-check` for automated validation.

## 3) Package

After a successful build, create a deployable ZIP:

```bash
# Bash (macOS/Linux/Git Bash on Windows)
./scripts/build-module.sh
./scripts/build-module.sh -p              # skip plugins (packaging only)
```

```powershell
# PowerShell (Windows native)
.\scripts\build-module.ps1
.\scripts\build-module.ps1 -SkipPlugins
```

Expected output:

`dist/fluent-commerce-<module-name>-<VERSION>.zip`

## Post-Build Validation

After Maven build completes, validate the output before handing off to deploy:

1. **Parse Maven output** — Check for:
   - `BUILD SUCCESS` (required to proceed)
   - `[WARNING]` lines — report to user, especially dependency convergence warnings
   - Skipped tests — flag as concern: "N tests were skipped; consider running full suite"
   - `BUILD FAILURE` — STOP, do not proceed to packaging

2. **JAR sanity check** — For extension modules, verify:
   - JAR file exists at expected path (`plugins/rules/target/*.jar`)
   - JAR size is non-zero and reasonable (> 1KB)
   - JAR manifest references expected rule classes

3. **Version pre-check** — Before build, call `/fluent-version-manage status` or read `module.json` version. If version matches the already-deployed version (from `fluent module list`), WARN: "Version {X} is already deployed. Bump version before building, or the deploy will be silently skipped."

Report build results as structured output: `{ success: true/false, warnings: [...], skippedTests: N, jarSize: N }` so downstream skills can consume it.

### Update status.json gates

If a feature context exists (`accounts/<PROFILE>/features/<slug>/status.json`):
- On `BUILD SUCCESS`: set `build: "PASSED"` and advance `status` to `"BUILT"` (if currently `IN_PROGRESS` or `APPROVED`)
- On `BUILD FAILURE`: set `build: "FAILED"` (do NOT advance `status`)
- Always update `updated` timestamp

## 4) Hand Off to Deploy Owner

After packaging completes:

- manual path: `/fluent-module-deploy`
- automated path: `npx @fluentcommerce/ai-skills flow-run --deploy --yes ...`

## Session Tracking

When invoked, log the following to the session tracking protocol (consumed by `/fluent-session`):

**On entry:**
```json
{ "skill": "<this-skill-name>", "timestamp": "<ISO-8601>", "arguments": { "<key>": "<value>", "...": "..." } }
```

**On exit:**
```json
{ "skill": "<this-skill-name>", "outcome": "<completed|failed|skipped>", "changesProduced": ["<seq-numbers>"], "toolCallsProduced": ["<seq-numbers>"], "nextRecommended": "<from-handoff-section>" }
```

All MCP tool calls made during execution should include `"skill": "<this-skill-name>"` in their tracking record for attribution. The `arguments` object should capture the key parameters actually passed (profile, retailer, entity type, etc.) — not a fixed schema. The `nextRecommended` value comes from the Handoff section below.

## Handoff

| Output Artifact | Consumed By | Path |
|----------------|-------------|------|
| Module ZIP artifact | `/fluent-pre-deploy-check` | `accounts/<PROFILE>/SOURCE/backend/<repo>/dist/<module-name>-<version>.zip` |
| Module ZIP artifact | `/fluent-module-deploy` | `accounts/<PROFILE>/SOURCE/backend/<repo>/dist/<module-name>-<version>.zip` |
| Build log (Maven output) | `/fluent-pre-deploy-check` | stdout from `mvn clean install` |

## Error Reporting

Errors from this skill follow the standard format:

| Field | Description |
|-------|-------------|
| `phase` | Skill phase where error occurred (e.g., `pre-check`, `compilation`, `test`, `packaging`) |
| `severity` | `CRITICAL` (blocks downstream), `HIGH` (needs fix), `MEDIUM` (advisory), `LOW` (informational) |
| `message` | Human-readable error description |
| `resolution` | Suggested fix or downstream skill to invoke |

## Common Build Failures

| Symptom | Likely cause | First check |
|---|---|---|
| `cannot find symbol` | import/type mismatch | validate changed classes and imports |
| dependency/module not found | wrong module scope/build root | run from `plugins/` and include `-am` where needed |
| tests fail after model changes | fixture/schema drift | update test fixtures and expected payloads |
| package script succeeds but ZIP missing expected assets | resource path mismatch | verify `resources/` contents and module build script inputs |

## Post-Execution: Feedback Capture

After completing this skill (whether success or failure), write a feedback record:

1. **Classify outcome:** `SUCCESS` (completed cleanly), `PARTIAL_SUCCESS` (completed after fixing issues), `FAILURE` (could not complete), `BLOCKED` (prereq missing), `USER_CORRECTED` (user overrode approach)
2. **Build record:** Create a `feedback-record-v1` JSON object with:
   - `skill`: `"fluent-build"`
   - `feature`: feature slug if applicable, null otherwise
   - `phases`: trace of each phase with PASS/FAIL/SKIP
   - `learnings`: any gotchas discovered during execution
   - `userCorrections`: any corrections the user provided
3. **Redact secrets:** Strip tokens, passwords, API keys. Keep business identifiers.
4. **Append** one JSON line to `accounts/<PROFILE>/feedback/fluent-build.jsonl`
5. **Update** `accounts/<PROFILE>/feedback/index.json` counters (create with `mkdir -p` if missing)

**Skip capture if:** The execution was trivially simple (e.g., user asked a question, no actual write operation happened).

## Known Pitfalls
<!-- feedback-promoted: managed section, updated by feedback loop -->

_(No promoted learnings yet.)_

<!-- end feedback-promoted -->
