Skip to content

Share pooling; add context to mark#3180

Open
bcb37 wants to merge 13 commits into
devfrom
wip/share-pooling-add-context-to-mark
Open

Share pooling; add context to mark#3180
bcb37 wants to merge 13 commits into
devfrom
wip/share-pooling-add-context-to-mark

Conversation

@bcb37

@bcb37 bcb37 commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the backend “mark” path to make experiment resolution consistent with the “assign” path by introducing an explicit context parameter, switching mark-time experiment selection to use context-scoped cached experiments, and adding integration coverage for state filtering and cross-context isolation.

Changes:

  • Add context to mark request validation and thread it through controllers → ExperimentAssignmentService.markExperimentPoint.
  • Replace mark-specific decision-point caching with getCachedValidExperiments(context) and consolidate selection logic in resolveExperimentForMarkPoint.
  • Expand integration tests to validate cancelled-experiment exclusion and prevent cross-context experiment pool contamination; update JS/Java clients to send context in mark requests.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/backend/test/integration/utils/index.ts Updates test helper to pass context into markExperimentPoint.
packages/backend/test/integration/UserNotDefined/index.ts Adjusts mark call signature in the “user not defined” integration case.
packages/backend/test/integration/index.test.ts Registers new integration test cases for mark behavior.
packages/backend/test/integration/Experiment/withinSubject/MetricQueriesCheck.ts Threads context through within-subject metric query mark calls.
packages/backend/test/integration/Experiment/stratification/MetricQueriesCheck.ts Threads context through stratification metric query mark calls.
packages/backend/test/integration/Experiment/markExperimentPoint/NoExperiment.ts Passes explicit context when marking in the NoExperiment case.
packages/backend/test/integration/Experiment/markExperimentPoint/index.ts Exposes new markExperimentPoint integration test cases.
packages/backend/test/integration/Experiment/markExperimentPoint/ContextContamination.ts Adds integration test ensuring no cross-context contamination for shared site/target.
packages/backend/test/integration/Experiment/markExperimentPoint/CancelledExperimentStateFilter.ts Adds integration test ensuring cancelled experiments are excluded from mark resolution.
packages/backend/test/integration/Experiment/experimentContext/ExperimentContextAssignments.ts Updates experiment-context integration flow to pass mark context.
packages/backend/src/api/services/ExperimentService.ts Simplifies cache invalidation to remove mark-cache key deletion.
packages/backend/src/api/services/ExperimentAssignmentService.ts Adds context-aware experiment resolution for mark and consolidates selection logic.
packages/backend/src/api/controllers/validators/MarkExperimentValidator.v6.ts Makes context required for v6 mark requests.
packages/backend/src/api/controllers/validators/MarkExperimentValidator.v5.ts Adds optional context for v5 mark requests (backward compatibility).
packages/backend/src/api/controllers/ExperimentClientController.v6.ts Passes validated context through to mark service call.
packages/backend/src/api/controllers/ExperimentClientController.v5.ts Passes optional context (currently defaulting to empty string) to mark service call.
docs/mark-context-refactor-plan.md Documents the rationale and phased plan for the mark-path refactor.
clientlibs/js/src/UpGradeClient/generateUUID.spec.ts Minor test cleanup (trailing whitespace removal).
clientlibs/js/src/types/requests.ts Adds context to the JS mark request body type.
clientlibs/js/src/ApiService/ApiService.ts Includes configured context in JS mark request bodies.
clientlibs/js/src/ApiService/ApiService.spec.ts Adds JS client tests verifying context is included in mark requests.
clientlibs/java/src/main/java/org/upgradeplatform/requestbeans/MarkExperimentRequest.java Adds context to the Java mark request bean and constructors.
clientlibs/java/src/main/java/org/upgradeplatform/client/ExperimentClient.java Threads client context into Java mark request construction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/backend/src/api/services/ExperimentAssignmentService.ts
Comment thread packages/backend/src/api/services/ExperimentAssignmentService.ts
bcb37 and others added 2 commits June 18, 2026 14:16
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@bcb37 bcb37 marked this pull request as ready for review June 18, 2026 19:10
@bcb37 bcb37 requested a review from danoswaltCL June 18, 2026 19:10
@bcb37 bcb37 changed the title Wip/share pooling add context to mark Share pooling add context to mark Jun 30, 2026
@bcb37 bcb37 changed the title Share pooling add context to mark Share pooling; add context to mark Jun 30, 2026
const dpExpExists = allExperimentsAtDP.filter((exp) => exp.id === experimentId);
if (!dpExpExists.length) {
const error = new Error(
`Experiment ID not provided for shared Decision Point in markExperimentPoint: ${userDoc.id}`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor thing but i don't think this error message matches what's happening. maybe this was the preexisting error but i think we mean experimentId not found among valid experiments.

* so the selected experiment is guaranteed to match what getAllExperimentConditions would have returned for
* the same user and decision point.
*/
private async resolveExperimentForMarkPoint(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of this sequence for the parts that the mark and assign calls need to do exactly the same is still implemented twice. can we get the important parts for selecting / filtering valid experiments and running through the pooling logic in one method so it really is guaranteed to match?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we could DRY this out a bit more for the cases where there's no experimentId

};
}

const [isUserExcluded, isGroupExcluded] = await this.checkUserOrGroupIsGloballyExcluded(userDoc, context);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if a user is globally excluded but is marking as if they got an assignment... what happens?

@bcb37 bcb37 Jul 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No enrollment records are created but a monitored decision point entry is.

@bcb37 bcb37 requested a review from zackcl July 10, 2026 13:26
@danoswaltCL

Copy link
Copy Markdown
Collaborator

so we will read and write to the same experiments cache in the assign and mark paths in this right? that would be great if i'm reading this correctly, I think that would halve the number of db fetches to select experiments. if my math is right, which it usually isn't, but regardless, a good thing.

@bcb37

bcb37 commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator Author

so we will read and write to the same experiments cache in the assign and mark paths in this right? that would be great if i'm reading this correctly, I think that would halve the number of db fetches to select experiments. if my math is right, which it usually isn't, but regardless, a good thing.

Yeah, I think that simplifies the cacheing quite a bit, given that we can get rid of one of the cache keys.

@bcb37 bcb37 requested review from Copilot and danoswaltCL July 10, 2026 19:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

packages/backend/test/unit/services/ExperimentAssignmentService.test.ts:1127

  • This test calls markExperimentPoint with the old argument order: the third argument should be a MARKED_DECISION_POINT_STATUS, but target (undefined) is being passed instead. The current test passes only because the method doesn’t validate status, and it risks masking real regressions in the mark path.
    const result = await testedModule.markExperimentPoint(
      { id: userId },
      site,
      target,
      condition,
      loggerMock,
      'context',
      undefined,
      undefined,
      undefined,
      clientError

Comment thread packages/backend/src/api/services/ExperimentAssignmentService.ts
Comment thread packages/backend/src/api/services/ExperimentAssignmentService.ts
Comment thread packages/backend/src/api/services/ExperimentAssignmentService.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor mark path to use context-aware caching and consolidate experiment selection logic

3 participants