function makeChange(doc, context, options) {
  const actor = getActorId(doc)
  if (!actor) {
    throw new Error('Actor ID must be initialized with setActorId() before making a change')
  }
  const state = copyObject(doc[STATE])
  state.seq += 1

  const change = {
    actor,
    seq: state.seq,
    startOp: state.maxOp + 1,
    deps: state.deps,
    time: (options && typeof options.time === 'number') ? options.time
                                                        : Math.round(new Date().getTime() / 1000),
    message: (options && typeof options.message === 'string') ? options.message : '',
    ops: context.ops
  }

  if (doc[OPTIONS].backend) {
    const [backendState, patch, binaryChange] = doc[OPTIONS].backend.applyLocalChange(state.backendState, change)
    state.backendState = backendState
    state.lastLocalChange = binaryChange
    // NOTE: When performing a local change, the patch is effectively applied twice -- once by the
    // context invoking interpretPatch as soon as any change is made, and the second time here
    // (after a round-trip through the backend). This is perhaps more robust, as changes only take
    // effect in the form processed by the backend, but the downside is a performance cost.
    // Should we change this?
    const newDoc = applyPatchToDoc(doc, patch, state, true)
    const patchCallback = options && options.patchCallback || doc[OPTIONS].patchCallback
    if (patchCallback) patchCallback(patch, doc, newDoc, true, [binaryChange])
    return [newDoc, change]

  } else {
    const queuedRequest = {actor, seq: change.seq, before: doc}
    state.requests = state.requests.concat([queuedRequest])
    state.maxOp = state.maxOp + countOps(change.ops)
    state.deps = []
    return [updateRootObject(doc, context ? context.updated : {}, state), change]
  }
}
Adds a new change request to the list of pending requests, and returns an
updated document root object.
The details of the change are taken from the context object `context`.
`options` contains properties that may affect how the change is processed; in
particular, the `message` property of `options` is an optional human-readable
string describing the change.