@Override
    protected AbstractConfigValue attemptPeekWithPartialResolve(String key) {
        // a partial resolve of a ConfigDelayedMergeObject always results in a
        // SimpleConfigObject because all the substitutions in the stack get
        // resolved in order to look up the partial.
        // So we know here that we have not been resolved at all even
        // partially.
        // Given that, all this code is probably gratuitous, since the app code
        // is likely broken. But in general we only throw NotResolved if you try
        // to touch the exact key that isn't resolved, so this is in that
        // spirit.

        // we'll be able to return a key if we have a value that ignores
        // fallbacks, prior to any unmergeable values.
        for (AbstractConfigValue layer : stack) {
            if (layer instanceof AbstractConfigObject) {
                AbstractConfigObject objectLayer = (AbstractConfigObject) layer;
                AbstractConfigValue v = objectLayer.attemptPeekWithPartialResolve(key);
                if (v != null) {
                    if (v.ignoresFallbacks()) {
                        // we know we won't need to merge anything in to this
                        // value
                        return v;
                    } else {
                        // we can't return this value because we know there are
                        // unmergeable values later in the stack that may
                        // contain values that need to be merged with this
                        // value. we'll throw the exception when we get to those
                        // unmergeable values, so continue here.
                        continue;
                    }
                } else if (layer instanceof Unmergeable) {
                    // an unmergeable object (which would be another
                    // ConfigDelayedMergeObject) can't know that a key is
                    // missing, so it can't return null; it can only return a
                    // value or throw NotPossibleToResolve
                    throw new ConfigException.BugOrBroken(
                            "should not be reached: unmergeable object returned null value");
                } else {
                    // a non-unmergeable AbstractConfigObject that returned null
                    // for the key in question is not relevant, we can keep
                    // looking for a value.
                    continue;
                }
            } else if (layer instanceof Unmergeable) {
                throw new ConfigException.NotResolved("Key '" + key + "' is not available at '"
                        + origin().description() + "' because value at '"
                        + layer.origin().description()
                        + "' has not been resolved and may turn out to contain or hide '" + key
                        + "'."
                        + " Be sure to Config#resolve() before using a config object.");
            } else if (layer.resolveStatus() == ResolveStatus.UNRESOLVED) {
                // if the layer is not an object, and not a substitution or
                // merge,
                // then it's something that's unresolved because it _contains_
                // an unresolved object... i.e. it's an array
                if (!(layer instanceof ConfigList))
                    throw new ConfigException.BugOrBroken("Expecting a list here, not " + layer);
                // all later objects will be hidden so we can say we won't find
                // the key
                return null;
            } else {
                // non-object, but resolved, like an integer or something.
                // has no children so the one we're after won't be in it.
                // we would only have this in the stack in case something
                // else "looks back" to it due to a cycle.
                // anyway at this point we know we can't find the key anymore.
                if (!layer.ignoresFallbacks()) {
                    throw new ConfigException.BugOrBroken(
                            "resolved non-object should ignore fallbacks");
                }
                return null;
            }
        }
        // If we get here, then we never found anything unresolved which means
        // the ConfigDelayedMergeObject should not have existed. some
        // invariant was violated.
        throw new ConfigException.BugOrBroken(
                "Delayed merge stack does not contain any unmergeable values");

    }