Experiments API gaps for the standalone portlet: archive/restore, PATCH side effects, goal operators, variant cap
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Description
The new Experiments portlet (#36987) turns /experiments/new into a routed, autosaving Configure screen and adds list actions the current backend cannot support. Four API gaps stand in the way — all other mutations already exist (create, PATCH, start, end, cancel, archive, delete, variants, promote, results).
1. Archive from DRAFT + restore/unarchive
Today archive is only allowed from ENDED, and no unarchive/restore method exists at all. The approved design archives from DRAFT and ENDED, and restores an ARCHIVED experiment back to DRAFT. Add both transitions to ExperimentsAPIImpl + ExperimentsResource.
Frontend gating note: the matrix AllowedActionsByExperimentStatus (core-web/libs/dotcms-models/src/lib/dot-experiments-constants.ts:256-287) is read by the existing UVE list menu. Do not widen the existing archive: [ENDED] key — the new transitions get new keys (archiveDraft, restore) so the old UI's menu cannot change.
2. PATCH side effects (autosave blocker)
Every PATCH /api/v1/experiments/{id} currently overwrites targetingConditions with []: ExperimentForm defaults it to a non-null empty list, so the resource's != null guard always fires, creating an empty Rule + ConditionGroup on every call. The new screen autosaves on edit, so this would create one Rule per keystroke pause. Fix so an absent targetingConditions leaves the stored value untouched.
Related, document-only: trafficAllocation can never be PATCHed to 0 (if (getTrafficAllocation() > 0)) — harmless, the design's minimum is 1.
3. Goal operators: validate, then extend
The Operator enum has only EQUALS / CONTAINS / EXISTS, and operators are never validated: an unsupported operator is silently accepted and then silently ignored, producing a goal that never converts with no error anywhere. Validate on write (400 on unsupported). Then extend with the operators the design offers — STARTS_WITH, ENDS_WITH, REGEX — wired through the metric/query layer so they actually evaluate. If extending is too large for this issue, validation+reject still lands here (it is the bug) and the new operators split out; the UI then trims to the supported set.
4. Variant cap enforcement
VARIANTS_NUMBER_MAX = 3 (ExperimentsAPIImpl.java:105) is only enforced in calcBayesian (:1344) — not in addVariant (:964). A user can build 5 variants, run for two weeks, and discover the failure when opening Results. Enforce the cap in addVariant with a clear error. Open question: the design says "Up to 5 Variants" — raising the cap requires validating the Bayesian implementation for 5 arms; decide before implementing (the UI ships with whatever cap this issue lands).
Acceptance Criteria
- Archive succeeds from
DRAFTandENDED. - A restore/unarchive endpoint moves
ARCHIVED→DRAFT. -
AllowedActionsByExperimentStatusgainsarchiveDraftandrestorekeys; existing keys byte-identical. - A
PATCHwithouttargetingConditionsdoes not create a Rule/ConditionGroup and leaves stored targeting untouched (integration test proving no new Rule rows). - An unsupported goal operator is rejected with a 400 (today: silently ignored).
-
addVariantrejects the variant that would exceedVARIANTS_NUMBER_MAX. - Integration tests for all of the above;
openapi.yamlregenerated (./mvnw compile -pl :dotcms-core -DskipTests) and committed with the annotation changes.
Priority
High — the PATCH fix blocks the Create/Update screen of #36987 (autosave is the creation mechanism).
Additional Context
- No dependency on #36823 — parallel work.
- Out of scope: pagination/permissions/enriched rows/counts (#36823); any frontend change beyond the two additive matrix keys.
- Testing:
./mvnw test -pl :dotcms-core -Dtest=ExperimentsAPIImplTest·./mvnw verify -pl :dotcms-integration -Dcoreit.test.skip=false -Dit.test=ExperimentAPIImpIntegrationTest
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with ExperimentsAPIImpl and ExperimentsResource, then inspect AllowedActionsByExperimentStatus in core-web/libs/dotcms-models/src/lib/dot-experiments-constants.ts. Run ExperimentsAPIImplTest and ExperimentAPIImpIntegrationTest before changing the archive, PATCH, operator, and variant paths. Done means all acceptance criteria pass, including unchanged existing action keys and regenerated openapi.yaml.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, typescript
- Domain
- backend-api-design, frontend, testing
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100