public function check(array $input)
    {
        // Automatic reset
        if (count($this->pending) === 0) {
            foreach (Arr::keys($this->nodes) as $name) {
                if (count($this->incomingEdges[$name]) === 0) {
                    $this->pending[] = $name;
                }
            }

            $this->checked = [];
            $this->results = [];
            $this->failed = false;
        }

        // Actual process
        while (count($this->checked) < count($this->nodes)) {
            if (count($this->pending) === 0) {
                throw new CoreException('Unable to resolve constraint graph.');
            }

            $this->iterate($input);

            if ($this->failed) {
                $this->pending = [];
                break;
            }
        }

        // Aggregate results
        $missing = [];
        $failed = [];

        array_map(function (SpecResult $result) use (&$missing, &$failed) {
            $missing[] = $result->getMissing();
            $failed[] = $result->getFailed();
        }, $this->checked);

        return new SpecResult(
            Arr::mergev($missing),
            Arr::mergev($failed),
            $this->failed ? SpecResult::STATUS_FAIL : SpecResult::STATUS_PASS
        );
    }