---
name: fluent-inventory-catalog
description: "Manage Fluent Commerce virtual inventory: catalogues, positions, segments, feeds, and control groups. Schema-gated — only runs when VirtualSegment type exists."
user-invocable: true
trigger-patterns:
  - "inventory catalog"
  - "virtual position"
  - "virtual segment"
  - "inventory feed"
  - "control group"
  - "segment allocation"
  - "channel inventory"
  - "inventory setup"
tags: [inventory, segments, virtual-catalogue, feeds]
scope: dev
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
planning-gate: mandatory
---

# Inventory Catalog Management

Manage Fluent Commerce virtual inventory structures: Virtual Catalogues, Virtual Positions, Virtual Segments, Inventory Feeds, and Control Groups. This skill handles discovery, creation, segment allocation, and feed pipeline management for inventory segmentation use cases (channel splits, regional allocation, pre-order waves).

---

## Pre-Flight (MANDATORY)

### 1. Schema Gate — VirtualSegment Check

**This skill MUST NOT proceed if the account schema lacks segment support.**

Introspect the GraphQL schema for the `VirtualSegment` type:

```
graphql.introspect({ type: "VirtualSegment" })
```

- **If `VirtualSegment` type exists:** proceed.
- **If NOT found:** STOP immediately with this message:

> Virtual Segments not available on this account's schema version. This feature requires platform version with segment support (expected April 2026+). Run `graphql.introspect` with `type: 'VirtualSegment'` to check availability.

Do NOT fall back to non-segment inventory operations. The entire skill is gated on segment support.

### 2. Environment Check

- Verify `FLUENT_PROFILE` is set. If not, BLOCK: `PREREQ_MISSING — Set FLUENT_PROFILE or run /fluent-profile first.`
- Read `accounts/<PROFILE>/memory/index.md` if it exists — apply account-specific learnings silently.

### 3. Project Knowledge Check

- Read `accounts/<PROFILE>/knowledge/` and find files where `relevant-skills` includes `fluent-inventory-catalog`.
- Read `knowledge/platform/domain-model.md` for entity relationships (VirtualCatalogue, VirtualPosition, InventoryFeed).
- Check `accounts/<PROFILE>/knowledge/` for account-specific overrides.

### 4. Feedback Check

- Check if `accounts/<PROFILE>/feedback/fluent-inventory-catalog.jsonl` exists.
- If yes, read last 20 records, extract top 3 relevant learnings, silently adjust approach.

### 5. Planning Gate

Before creating or updating any inventory structures:

1. **Feature context:** If `accounts/<PROFILE>/features/<slug>/status.json` exists for this work, check `spec: "APPROVED"` and `plan: "APPROVED"`. BLOCK if missing.
2. **Multi-artifact work** (inventory + rules + workflows): STOP. Run `/fluent-feature-plan` first.
3. **Standalone inventory-only work:** Create a task plan at `accounts/<PROFILE>/tasks/<YYYY-MM-DD>-inventory-catalog-<slug>.md` with: what will be created/changed, expected segment structure, rollback steps. Get user approval before proceeding.
4. **Read-only (Discover mode):** No planning gate required.

---

## Modes

### Mode 1: Discover (Read-Only)

Explore existing inventory topology. No planning gate required.

#### 1.1 List Virtual Catalogues

```graphql
query {
  virtualCatalogues(first: 20) {
    edges {
      node {
        id
        ref
        name
        type
        status
        retailerRefs
        networkIds
        virtualPositions(first: 5) {
          edges {
            node {
              ref
              quantity
              segments(first: 10) {
                edges {
                  node {
                    type
                    value
                    quantity
                    availableOn
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
```

Present as a summary table: ref, name, type, status, position count.

#### 1.2 Get Position with Segments

```graphql
query($ref: String!, $catalogue: VirtualCatalogueKey!) {
  virtualPosition(ref: $ref, catalogue: $catalogue) {
    id
    ref
    productRef
    quantity
    groupRef
    segments(first: 100) {
      edges {
        node {
          type
          value
          availableOn
          quantity
          createdOn
          updatedOn
        }
      }
    }
  }
}
```

Present segment breakdown as a table: type, value, availableOn, quantity.

#### 1.3 Search Virtual Inventory (ATP)

```graphql
query($productRef: String!, $catalogueRef: String!) {
  searchVirtualInventory(productRef: $productRef, catalogueRef: $catalogueRef) {
    edges {
      node {
        location {
          ref
          name
        }
        virtualPositions {
          ref
          quantity
          segments(first: 50) {
            edges {
              node {
                type
                value
                quantity
                availableOn
              }
            }
          }
        }
      }
    }
  }
}
```

#### 1.4 List Inventory Feeds

```graphql
query {
  inventoryFeeds(first: 20) {
    edges {
      node {
        ref
        name
        status
        dataFormat
        frequencyCronExpression
        source { ... }
        destination { ... }
        runs(first: 5) {
          edges {
            node {
              ref
              status
              type
              count
              executionTime
              errorMessage
              completedOn
            }
          }
        }
      }
    }
  }
}
```

Present feeds as: ref, name, status, dataFormat, schedule, last run status/time.

#### 1.5 List Control Groups

```graphql
query {
  controlGroups(first: 20) {
    edges {
      node {
        id
        ref
        name
        description
        controls(first: 50) {
          edges {
            node {
              id
              ref
              name
              description
            }
          }
        }
      }
    }
  }
}
```

---

### Mode 2: Build (Create/Update)

Create or update inventory structures. **Planning gate required.**

#### 2.1 Create Virtual Catalogue

Required inputs (ask user for each):
- `ref` — unique reference (SCREAMING_SNAKE or kebab-case per naming conventions)
- `name` — human-readable name
- `type` — catalogue type
- `workflowRef` — workflow driving the catalogue
- `inventoryCatalogueRef` — source inventory catalogue
- `productCatalogueRef` — product catalogue to link
- `networkIds` — array of network IDs
- `retailerRefs` — array of retailer references

Use `graphql.query` with `createVirtualCatalogue` mutation.

#### 2.2 Create/Update Virtual Positions

```graphql
mutation($input: CreateVirtualPositionInput!) {
  createVirtualPosition(input: $input) {
    id
    ref
    quantity
    status
  }
}
```

Input shape:
```json
{
  "ref": "POSITION_REF",
  "catalogue": { "ref": "CATALOGUE_REF" },
  "type": "DEFAULT",
  "quantity": 100,
  "productRef": "PRODUCT_SKU",
  "groupRef": "GROUP_REF",
  "segments": [
    {
      "segment": { "type": "CHANNEL", "value": "ONLINE" },
      "availableOn": null,
      "quantity": 80
    }
  ]
}
```

For updates:
```graphql
mutation($input: UpdateVirtualPositionInput!) {
  updateVirtualPosition(input: $input) {
    id
    ref
    quantity
  }
}
```

#### 2.3 Create Inventory Feed

```graphql
mutation($input: CreateInventoryFeedInput!) {
  createInventoryFeed(input: $input) {
    ref
    status
  }
}
```

Required: ref, name, status, dataFormat (`DELTA` or `FULL`), source (type, url, credentials), destination (type, catalogueRef, locationRef), frequencyCronExpression.

#### 2.4 Create Feed Run

```graphql
mutation($input: CreateInventoryFeedRunInput!) {
  createInventoryFeedRun(input: $input) {
    ref
    status
  }
}
```

#### 2.5 Create Control Groups and Controls

Use the appropriate `createControlGroup` and `createControl` mutations. Ask user for: ref, name, description, and nested controls.

---

### Mode 3: Segment (Allocation Management)

Manage segment allocations on existing positions. **Planning gate required for writes.**

#### Segment Types

| Type | Purpose | Example Values |
|------|---------|----------------|
| `CHANNEL` | Split inventory between sales channels | `ONLINE`, `STORE`, `MARKETPLACE` |
| `REGION` | Allocate by geographic region | `AU`, `US`, `UK`, `EU` |
| `PREORDER` | Pre-order wave availability | `WAVE1`, `WAVE2` (with `availableOn` date) |

#### Uniqueness Constraint

The combination of `segment(type + value)` + `availableOn` must be unique within a single VirtualPosition. Duplicate combinations in an upsert will update the existing segment's quantity (not create a new one).

#### 3.1 Channel-Based Segmentation

Split inventory between online and store:

```json
{
  "segments": [
    { "segment": { "type": "CHANNEL", "value": "ONLINE" }, "quantity": 80 },
    { "segment": { "type": "CHANNEL", "value": "STORE" }, "quantity": 20 }
  ]
}
```

Always verify: segment quantities should sum to (or be less than) position total quantity.

#### 3.2 Region-Based Segmentation

```json
{
  "segments": [
    { "segment": { "type": "REGION", "value": "AU" }, "quantity": 50 },
    { "segment": { "type": "REGION", "value": "US" }, "quantity": 30 },
    { "segment": { "type": "REGION", "value": "UK" }, "quantity": 20 }
  ]
}
```

#### 3.3 Date-Based Pre-Order

```json
{
  "segments": [
    { "segment": { "type": "PREORDER", "value": "WAVE1" }, "availableOn": "2026-04-15T00:00:00Z", "quantity": 100 },
    { "segment": { "type": "PREORDER", "value": "WAVE2" }, "availableOn": "2026-05-01T00:00:00Z", "quantity": 200 }
  ]
}
```

#### 3.4 Combined Segmentation (Channel + Date)

```json
{
  "segments": [
    { "segment": { "type": "CHANNEL", "value": "ONLINE" }, "availableOn": "2026-04-15T00:00:00Z", "quantity": 50 },
    { "segment": { "type": "CHANNEL", "value": "STORE" }, "availableOn": "2026-04-15T00:00:00Z", "quantity": 30 }
  ]
}
```

#### 3.5 Bulk Segment Updates

For updating segments across multiple positions matching a pattern:

1. Query positions by catalogue ref and optional productRef/groupRef filter.
2. For each position, build the segment upsert payload.
3. Execute `updateVirtualPosition` mutations sequentially (NOT in parallel — avoid rate limits).
4. Report: positions updated, segments created vs updated, any failures.

---

## Inventory Feed Pipeline Reference

```
InventoryFeed (defines pipeline)
  ref, name, status
  source: { type, url, credentials }
  destination: { type, catalogueRef, locationRef }
  dataFormat: DELTA | FULL
  frequencyCronExpression: "0 */2 * * *"
  runs: InventoryFeedRun[]
    ref, status, type
    count (records processed)
    executionTime (ms)
    errorMessage (if failed)
    completedOn
```

- `DELTA` feeds process only changes since last run.
- `FULL` feeds replace the entire dataset on each run.
- Cron expressions follow standard 5-field format.

---

## Error Handling

| Error | Cause | Resolution |
|-------|-------|------------|
| Duplicate segment key | Same type+value+availableOn already exists | This is an upsert — quantity will be updated, not an error |
| Missing catalogue ref | Position created without catalogue | Always specify `catalogue: { ref }` in input |
| Invalid cron expression | Malformed `frequencyCronExpression` | Validate cron syntax before submitting (5-field standard) |
| Feed run on inactive feed | Attempting to trigger run on a feed with non-active status | Activate the feed first via update mutation |
| Schema type not found | `VirtualSegment` absent from schema | Account lacks segment support — skill cannot proceed (see Pre-Flight) |

---

## Post-Execution

### Feedback Capture

After any write operation, append a feedback record to `accounts/<PROFILE>/feedback/fluent-inventory-catalog.jsonl`:

```json
{
  "$schema": "feedback-record-v1",
  "skill": "fluent-inventory-catalog",
  "mode": "build|segment",
  "outcome": "SUCCESS|PARTIAL_SUCCESS|FAILURE|USER_CORRECTED",
  "context": { "catalogueRef": "...", "positionCount": 0, "segmentTypes": [] },
  "learning": "Brief description of what happened",
  "confidence": "OBSERVED",
  "timestamp": "ISO8601"
}
```

### Change Tracking

Report all changes made:
- Catalogues created/updated
- Positions created/updated with segment counts
- Feeds created/triggered
- Control groups/controls created

Flag any destructive changes (segment quantity reductions, feed deactivations).

### Handoff

- After creating catalogue + positions: `NEXT: /fluent-workflow-builder` if workflow needed.
- After feed setup: `NEXT: /fluent-system-monitoring` to watch feed runs.
- After segment allocation: `REVIEW: segment summary table` for user verification.

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

_(No promoted learnings yet.)_

<!-- end feedback-promoted -->
