@apex-inc/mcp-server 0.27.2 → 0.27.3
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.
- package/dist/prompts.js +4 -4
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +24 -8
- package/dist/tools.js.map +1 -1
- package/guardrails/experiment-rules.md +11 -0
- package/package.json +1 -1
- package/skills/apex-experimentation/SKILL.md +12 -2
|
@@ -13,6 +13,17 @@
|
|
|
13
13
|
## Implementation
|
|
14
14
|
- Resolve the variant with the canonical Apex resolver (`useApexVariant` on web,
|
|
15
15
|
`Apex.getVariant()` on mobile). Both fire the `experiment_exposure` event.
|
|
16
|
+
- Merchants still write `const variant = useApexVariant("exp_…")` and branch.
|
|
17
|
+
First HTML is flicker-free only when the server already assigned the visitor
|
|
18
|
+
and passed that arm (`initialVariant` or `<ApexProvider assignments>`).
|
|
19
|
+
Mint or read `apex_vid` on the document request and assign with the same
|
|
20
|
+
rules as `GET /api/experiments/{id}/assign`. If you use Next.js,
|
|
21
|
+
`npm install @apex-inc/next @apex-inc/react`, then
|
|
22
|
+
`apexVisitorMiddleware`, `assignExperiments`,
|
|
23
|
+
`<ApexProvider assignments>`. The hook alone is not flicker-free. A
|
|
24
|
+
client-only SPA cannot know the arm before first HTML; do not promise
|
|
25
|
+
no flicker there. Do not hide the page until assign (worse LCP).
|
|
26
|
+
Creating the experiment via MCP does not remove flicker.
|
|
16
27
|
- The variant must fall back to control on ineligible / error.
|
|
17
28
|
- For VISUAL changes, confirm the arms actually differ — screenshot both. Class
|
|
18
29
|
overrides can silently no-op (e.g. when the codebase doesn't tailwind-merge),
|
package/package.json
CHANGED
|
@@ -73,7 +73,13 @@ Interactive flows: MCP prompts `new-experiment` and `experiment-review` orchestr
|
|
|
73
73
|
- **Target URL is this workspace.** `target_url` must be a host named on the **active** workspace (`list_workspace_environments` + the workspace site). If the merchant already named a workspace, switch to it — do not ask which workspace again. If they have multiple hosts on that workspace, ask which URL. Never guess `apex.inc` or any other workspace's domain.
|
|
74
74
|
- **Mobile/Capacitor experiments capture on-device.** When the experiment runs on an authed in-app screen (servers can't reach it), tell the dev to call `Apex.captureVariantScreenshot({ experimentId, variantKey })` on the variant's screen, keyed to the resolved variant in a `useEffect`, in a debug build (`Apex.initialize({ ..., debug: true })`). It no-ops in production and lands the shot on the dashboard card + gallery like web/agent captures.
|
|
75
75
|
- **Exposure auto-fires.** When a variant resolves via `useApexVariant` (web) or `Apex.getVariant()` (mobile), the SDK fires the canonical `experiment_exposure` event — the denominator for results. You don't fire it manually.
|
|
76
|
-
- **
|
|
76
|
+
- **First HTML / flicker.** Merchants still write `const variant = useApexVariant("exp_…")` and branch in React. That hook is not flicker-free by itself. First HTML is flicker-free only when it is already the assigned arm.
|
|
77
|
+
- **SSR (Next, Remix):** on the document request, mint or read the `apex_vid` cookie. Assign with the same rules as `GET /api/experiments/{id}/assign`. Pass that arm: `useApexVariant(id, { initialVariant, search })` or `<ApexProvider assignments={{ [id]: variant }}>`. `{ search }` also makes `_apex_preview` match on first HTML. Without the server arm, the first HTML is control; after `/assign` returns, React swaps. That swap is the flicker.
|
|
78
|
+
- **If you use Next.js:** `npm install @apex-inc/next` (visitor middleware + `assignExperiments`). Pass the result to `<ApexProvider assignments>`.
|
|
79
|
+
- **Client-only SPA:** the hook cannot know the arm before first HTML. Do not promise no flicker.
|
|
80
|
+
- **Snippet mode** (Apex mutates the DOM) is a different path. Do not conflate. Do not hide the page until `/assign` returns as the React-hook promise (worse LCP).
|
|
81
|
+
- **MCP does not serve the visitor page.** `create_experiment` / `activate_experiment` do not remove flicker. The merchant app must still pass the server arm.
|
|
82
|
+
- Pass the server arm into the hook or provider. `@apex-inc/react@0.4.3` accepts `initialVariant` and `ApexProvider assignments`.
|
|
77
83
|
- **Don't launch a dead experiment.** `activate_experiment` is gated on `verify_experiment_wiring`. Code-wired (SDK-hook) web experiments are safe to activate before their code ships: the server holds them in `pending_deployment` ("Waiting on deploy"). The 14-day clock starts at the first **recorded** visit (a tester on a named Beta site, or a live visit) — not merge, not activate. Testers on a named Beta site count in the winner. Localhost/dev is recorded as Dev and does not start the window or decide the winner. Assign with no Origin is Unclassified (no enrollment). Backend assign must send `environment` or `x-apex-web-environment`. Non-SDK experiments with unwired arms are refused (pass `force: true` to override). Run `verify_experiment_wiring({ experimentId })` after the deploy lands to confirm both arms are live.
|
|
78
84
|
|
|
79
85
|
### Journey-arm experiments (any surface)
|
|
@@ -126,6 +132,8 @@ Omitting `intent` when it's required returns 409 `intent_required` naming both.
|
|
|
126
132
|
|
|
127
133
|
`GET /api/experiments/{experimentId}/assign` returns `{ variant, experimentId, visitorId }`. Assignment is **deterministic** from a stable visitor id (cookie `apex_vid` in browsers).
|
|
128
134
|
|
|
135
|
+
The same assign call is how a Next/Remix document request gets flicker-free first HTML: read or mint `apex_vid`, assign, pass the arm into `useApexVariant` / `ApexProvider`. If you use Next.js, `@apex-inc/next` does that. See First HTML / flicker above.
|
|
136
|
+
|
|
129
137
|
For **server-side** sends (e.g. PLG email or API-triggered notifications):
|
|
130
138
|
|
|
131
139
|
1. Use a **stable string per recipient** as the visitor id (e.g. hashed user id). Reuse the same id for every assignment call for that user for that experiment.
|
|
@@ -137,7 +145,7 @@ Then branch notification copy or UI on `variant` (`control` vs `variant_b`).
|
|
|
137
145
|
## Instrumentation checklist
|
|
138
146
|
|
|
139
147
|
1. **Create and activate** the experiment in Apex (UI or MCP).
|
|
140
|
-
2. **Assign variant** before rendering the experience.
|
|
148
|
+
2. **Assign variant** before rendering the experience. On SSR, that means on the document request, then pass the arm into the hook or provider.
|
|
141
149
|
3. **Track primary metric** events with consistent names (e.g. `notification_sent`, `notification_opened`, `goal_completed`) and include `experimentId` and `variant` in properties when possible.
|
|
142
150
|
4. **Log a prediction** before launch when using the full intelligence loop (calibration).
|
|
143
151
|
5. **Decide** with `get_results` / dashboard — avoid peeking without a rule (pre-registered sample size, Bayesian policy, or fixed run duration).
|
|
@@ -152,6 +160,8 @@ Match Apex UI terminology in user-facing copy: e.g. **Adaptive traffic allocatio
|
|
|
152
160
|
- Declaring an SDK / Cursor draft ready from hosted screenshots of a public URL. The variant is local until deploy — attach localhost shots with `attach_experiment_asset`.
|
|
153
161
|
- Starting an experiment without a **clear primary metric** tied to the belief.
|
|
154
162
|
- Using different visitor ids for the same user across channels (breaks consistent assignment).
|
|
163
|
+
- Promising no flicker from `useApexVariant` without passing a server arm. Creating the experiment via MCP does not remove flicker.
|
|
164
|
+
- Hiding the page until `/assign` returns (worse LCP; not the React-hook promise).
|
|
155
165
|
- Changing variant implementation mid-flight without versioning (invalidates analysis).
|
|
156
166
|
- Only using p-values without effect size or business context.
|
|
157
167
|
|