Skip to content

feat(sales): subscription gap audit + four workflows - #130

Open
bpalmer77fluid wants to merge 2 commits into
Fluid-WeCommerce:mainfrom
bpalmer77fluid:feat/sales-subscription-gap
Open

feat(sales): subscription gap audit + four workflows#130
bpalmer77fluid wants to merge 2 commits into
Fluid-WeCommerce:mainfrom
bpalmer77fluid:feat/sales-subscription-gap

Conversation

@bpalmer77fluid

Copy link
Copy Markdown

One skill and four workflows, all built and run against a live Fluid company today.

sales/subscription-gap/SKILL.md
sales/subscription-gap/references/replenishment-classes.md
sales/subscription-gap/references/measuring-cadence.md
workflows/subscription-gap.workflow.json           8 steps
workflows/setup-tiktok-shop.workflow.json          8 steps
workflows/setup-instagram-affiliate.workflow.json  7 steps
workflows/subscription-sms.workflow.json          10 steps

The skill

Subscription gap audit finds the products a merchant sells which run out and get
rebought, but that no customer can put on a schedule. On the personal-care catalog I built
this against, 15 of 26 products were replenishable with zero carrying a subscription
plan — $151 of list price no customer could reorder.

Folder shape because the term lists and the SQL are lookup material the agent doesn't need
in context on every turn.

The workflows

setup-tiktok-shop — screen the catalog against TikTok commerce policy, pick the category
gate and its real timeline, set the creator qualification gate and commission tiers from live
prices, build the enrollment page and merchant console, close with an honest blocker list.

setup-instagram-affiliate — Meta commerce policy is a genuinely different ruleset, not
TikTok's with the names swapped. Meta ended native checkout in August 2025, so every tagged
tap lands on the merchant's own domain and the work is link attribution, not order
reconciliation
.

subscription-sms — detect the messaging rail the merchant already has, clear the two
blockers that actually stop SMS launches (sender registration and consent), scope the
actions, deploy a branded droplet.

subscription-gap — the 8-step build that pairs with the skill.

What the live runs taught, and why the prompts look the way they do

Most of these were expensive to learn because nothing errored — the output just came back
confident and wrong.

Pin /api/v202604/company/products + /{id}. The shop-host /api/products payload
embeds the entire country atlas — roughly 25KB per product — and the admin list endpoint
carries no variants[] at all. Only the detail endpoint has everything. Choosing wrong
doesn't fail, it just quietly gives you nothing usable.

description is an object with a .body, not a string. String() coercion yields
[object Object], which silently reduces classification to title-only. A 26-product catalog
classified cleanly on half the evidence and looked fine.

price is null at product level on the shop-host payload; the real value is in
variants[].variant_countries, a dict keyed by country code. Reading the product field
returns $0.00 for an entire catalog and a gap report quoting "$0 of list price."

Eligibility and reviewability must stay separate numbers. A content-review flag should
never reduce the count of what's eligible to list — they answer different questions.

Weight-management products are prohibited outright on TikTok Shop. Not restricted.
Banned. For a book full of weight-management merchants that's a screening question, not a
footnote.

Drop rank-based creator gating when the company has no distributor ranks rather than
offering a qualification path that doesn't exist. Check is_mlm and the distributor count
instead of assuming.

Don't recommend on-platform autoship after proving the plans it needs can't be created.
Every documented v2026-04 subscription path is a customer-instance operation — cancel, pause,
skip, retry. There is no endpoint to create a product subscription plan.

Enrollment belongs on the storefront, never behind admin login. Creators have no admin
session. The merchant console is the droplet; the enrollment page is a theme page.

A launch checklist that reads clean while a 21-day approval sits unstarted is worse than no
checklist.
The closing step's acceptance criteria enforce that.

Design decisions worth a reviewer's eye

Structure beats text. is_bundle / product_bundles / bundle_config are authoritative
when populated. Text classification is only the fallback — necessary because Fluid returns
category: null and tags: [] on a real import.

Text matches are scored, not hand-ordered. Title evidence outranks description evidence;
longer terms outrank shorter. This isn't premature generality — a hand-ordered version failed
in both directions at once on a real catalog. It classified two wax kits as bundles, hiding
genuine recurring revenue, while a real multi-product set carrying no bundle word fell through
to treatment and would have been offered as a subscription. Subscribing a bundle re-ships a
durable the customer already owns, which is how a subscription earns a cancellation.

Word boundaries, case-sensitive acronyms. Substring matching finds TENS inside
"softens", "brightens" and "moistens", which told a skincare merchant their lip balm was a
medical device.

Coverage is checked at product AND variant level. A plan attaches at either. Checking one
under-reports coverage and manufactures a gap that isn't there.

It refuses to invent revenue. The estimate needs an attach rate and a buyer count, both
from order history. With no reporting database connected the skill says so and gives the
defensible version — N products and $X of list price outside any schedule — rather than
borrowing an industry attach rate.

Add-on before skip. Only adding an item creates incremental revenue. A flow that opens
with "want to skip?" reduces the merchant's revenue very efficiently.

Where these apply

Any merchant selling consumables — personal care, supplements, food and beverage, pet,
household, cosmetics. The subscription-gap trigger is computable from the catalog alone:
a replenishable product with no subscription plan. Weak fit on apparel and hardgoods,
which are mostly durables — the skill correctly returns NO GAP rather than inventing one.

The channel workflows need no comp plan and no distributors, which is why they port to
another company in minutes.

Verification

  • python3 scripts/validate_catalog.py43 skills, 11 workflows, passes
  • The 14 contract tests pass: python3 -m unittest discover -s scripts -p 'test_*.py'
  • All four workflows validated for stored-shape parity against the known-good
    subscription-sms.workflow.json; DAGs sort clean
  • Classification logic separately unit-tested (17 tests) and mutation-tested outside this
    repo: removing title weighting fails 2, removing ambiguity flagging fails 3, removing the
    structural bundle check fails 2
  • Exercised against two live Fluid catalogs — a 31-SKU and a 26-SKU personal-care book

Open question for maintainers

Four workflows is a lot to land at once. If you'd rather take the skill alone and have the
workflows as a follow-up PR, say so and I'll split it — they're independent.

Finds the products a merchant sells that run out and get rebought but that no
customer can put on a schedule — the recurring revenue already sitting in the
catalog. Most merchants run half a razor-and-blades business: the refill is on
subscription and every other consumable is one-time-only.

Folder shape, because the term lists and the SQL are lookup material the agent
does not need in context every turn:
  sales/subscription-gap/SKILL.md
  sales/subscription-gap/references/replenishment-classes.md
  sales/subscription-gap/references/measuring-cadence.md
  workflows/subscription-gap.workflow.json   (8 steps, optional)

Design notes worth reviewing:

- Structure beats text. is_bundle / product_bundles / bundle_config are
  authoritative; text classification is the fallback, because Fluid returns
  category: null and tags: [] on a real import.
- Text matches are SCORED, not hand-ordered: title evidence outranks description
  evidence, longer terms outrank shorter. Hand-ordering failed in both directions
  on a real catalog — it called two wax kits bundles (hiding real revenue) and
  called a genuine multi-product set a treatment (which would have put a
  subscription on a bundle).
- Anything the title did not decide returns NEEDS REVIEW rather than a guess.
- Subscription coverage is checked at product AND variant level; a plan attaches
  at either, and checking only one under-reports coverage.
- The skill refuses to quote a revenue number without an attach rate and buyer
  count from the merchant's own order history, and gives the defensible
  SKU-and-list-price version instead.
- Add-on is offered BEFORE any skip or pause option: only adding an item creates
  incremental revenue.

Verified against a live 31-SKU Fluid catalog and a 24-SKU personal-care catalog.
Catalog validation and the 14 contract tests pass locally.
… SMS

Three channel workflows built and run against a live Fluid company today, added
alongside the subscription-gap skill already in this PR.

- setup-tiktok-shop (8 steps) — screen the catalog against TikTok commerce
  policy, pick the category gate and its real timeline, set the creator
  qualification gate and commission tiers from live prices, build the enrollment
  page and merchant console, close with an honest blocker list.
- setup-instagram-affiliate (7 steps) — Meta commerce policy is a different
  ruleset, not TikTok's with the names swapped: Meta ended native checkout in
  Aug 2025, so the work is link attribution rather than order reconciliation.
- subscription-sms (10 steps) — detect the messaging rail, clear the two
  blockers that actually stop SMS launches (sender registration and consent),
  scope the actions, deploy a branded droplet.

What the live runs taught, encoded in the step prompts:

- pin /api/v202604/company/products + /{id}. The shop-host payload embeds the
  entire country atlas (~25KB/product) and the admin LIST endpoint has no
  variants[] at all. Picking wrong does not error.
- description is an object with .body, not a string; price is null at product
  level and lives in variants[].variant_countries keyed by country code. Read
  either naively and you get confident, precise-looking, wrong output.
- eligibility and reviewability stay separate numbers — a review flag must never
  reduce the eligible count.
- weight-management products are prohibited outright on TikTok Shop, not
  restricted.
- drop rank-based creator gating when the company has no distributor ranks
  rather than offering a qualification path that does not exist.
- do not recommend on-platform autoship after proving the subscription plans it
  needs cannot be created — Fluid has no endpoint for that.
- enrollment belongs on the storefront, never behind admin login: creators have
  no admin session.
- a launch checklist that reads clean while a 21-day approval sits unstarted is
  worse than no checklist.

Catalog validation and the 14 contract tests pass locally: 43 skills, 11
workflows.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant