public <T> CompletableFuture<Boolean> recordInitialState(final UUID accountIdentifier,
      final byte deviceId,
      final String experimentName,
      final boolean inExperimentGroup,
      final T initialState) throws JsonProcessingException {

    final AttributeValue initialStateAttributeValue =
        AttributeValue.fromS(SystemMapper.jsonMapper().writeValueAsString(initialState));

    final AttributeValue inExperimentGroupAttributeValue = AttributeValue.fromBool(inExperimentGroup);

    return dynamoDbAsyncClient.putItem(PutItemRequest.builder()
            .tableName(tableName)
            .item(Map.of(
                KEY_EXPERIMENT_NAME, AttributeValue.fromS(experimentName),
                ATTR_ACI_AND_DEVICE_ID, buildSortKey(accountIdentifier, deviceId),
                ATTR_IN_EXPERIMENT_GROUP, inExperimentGroupAttributeValue,
                ATTR_INITIAL_STATE, initialStateAttributeValue,
                ATTR_TTL, AttributeValue.fromN(String.valueOf(clock.instant().plus(FINAL_SAMPLE_TTL).getEpochSecond()))))
            .conditionExpression("(attribute_not_exists(#inExperimentGroup) OR #inExperimentGroup = :inExperimentGroup) AND (attribute_not_exists(#initialState) OR #initialState = :initialState) AND attribute_not_exists(#finalState)")
            .expressionAttributeNames(Map.of(
                "#inExperimentGroup", ATTR_IN_EXPERIMENT_GROUP,
                "#initialState", ATTR_INITIAL_STATE,
                "#finalState", ATTR_FINAL_STATE))
            .expressionAttributeValues(Map.of(
                ":inExperimentGroup", inExperimentGroupAttributeValue,
                ":initialState", initialStateAttributeValue))
            .build())
        .thenApply(ignored -> true)
        .exceptionally(throwable -> {
          if (ExceptionUtils.unwrap(throwable) instanceof ConditionalCheckFailedException) {
            return false;
          }

          throw ExceptionUtils.wrap(throwable);
        });
  }
@Test
  void recordInitialState() throws JsonProcessingException {
    final String experimentName = "test-experiment";
    final UUID accountIdentifier = UUID.randomUUID();
    final byte deviceId = (byte) ThreadLocalRandom.current().nextInt(Device.MAXIMUM_DEVICE_ID);
    final boolean inExperimentGroup = ThreadLocalRandom.current().nextBoolean();
    final int bounciness = ThreadLocalRandom.current().nextInt();

    assertTrue(pushNotificationExperimentSamples.recordInitialState(accountIdentifier,
            deviceId,
            experimentName,
            inExperimentGroup,
            new TestDeviceState(bounciness))
        .join(),
        "Attempt to record an initial state should succeed for entirely new records");

    assertEquals(new PushNotificationExperimentSample<>(accountIdentifier, deviceId, inExperimentGroup, new TestDeviceState(bounciness), null),
        getSample(accountIdentifier, deviceId, experimentName, TestDeviceState.class));

    assertTrue(pushNotificationExperimentSamples.recordInitialState(accountIdentifier,
                deviceId,
                experimentName,
                inExperimentGroup,
                new TestDeviceState(bounciness))
            .join(),
        "Attempt to re-record an initial state should succeed for existing-but-unchanged records");

    assertEquals(new PushNotificationExperimentSample<>(accountIdentifier, deviceId, inExperimentGroup, new TestDeviceState(bounciness), null),
        getSample(accountIdentifier, deviceId, experimentName, TestDeviceState.class),
        "Recorded initial state should be unchanged after repeated write");

    assertFalse(pushNotificationExperimentSamples.recordInitialState(accountIdentifier,
            deviceId,
            experimentName,
            inExperimentGroup,
            new TestDeviceState(bounciness + 1))
        .join(),
        "Attempt to record a conflicting initial state should fail");

    assertEquals(new PushNotificationExperimentSample<>(accountIdentifier, deviceId, inExperimentGroup, new TestDeviceState(bounciness), null),
        getSample(accountIdentifier, deviceId, experimentName, TestDeviceState.class),
        "Recorded initial state should be unchanged after unsuccessful write");

    assertFalse(pushNotificationExperimentSamples.recordInitialState(accountIdentifier,
            deviceId,
            experimentName,
            !inExperimentGroup,
            new TestDeviceState(bounciness))
        .join(),
        "Attempt to record a new group assignment should fail");

    assertEquals(new PushNotificationExperimentSample<>(accountIdentifier, deviceId, inExperimentGroup, new TestDeviceState(bounciness), null),
        getSample(accountIdentifier, deviceId, experimentName, TestDeviceState.class),
        "Recorded initial state should be unchanged after unsuccessful write");

    final int finalBounciness = bounciness + 17;

    pushNotificationExperimentSamples.recordFinalState(accountIdentifier,
            deviceId,
            experimentName,
            new TestDeviceState(finalBounciness))
        .join();

    assertFalse(pushNotificationExperimentSamples.recordInitialState(accountIdentifier,
                deviceId,
                experimentName,
                inExperimentGroup,
                new TestDeviceState(bounciness))
            .join(),
        "Attempt to record an initial state should fail for samples with final states");

    assertEquals(new PushNotificationExperimentSample<>(accountIdentifier, deviceId, inExperimentGroup, new TestDeviceState(bounciness), new TestDeviceState(finalBounciness)),
        getSample(accountIdentifier, deviceId, experimentName, TestDeviceState.class),
        "Recorded initial state should be unchanged after unsuccessful write");
  }