Code review comment: Unfortunately, Java requires variables referenced in lambdas to be effectively final :-(

Code under review:
void doConverge(NodeAgentContext context) {
        NodeSpec node = context.node();
        Optional<Container> container = getContainer(context);

        
        if (currentRebootGeneration < node.currentRebootGeneration())
            currentRebootGeneration = node.currentRebootGeneration();

        
        
        if (currentRestartGeneration.isPresent() != node.currentRestartGeneration().isPresent() ||
                currentRestartGeneration.map(current -> current < node.currentRestartGeneration().get()).orElse(false))
            currentRestartGeneration = node.currentRestartGeneration();

        if (!node.equals(lastNode)) {
            logChangesToNodeSpec(context, lastNode, node);
            lastNode = node;
        }

        switch (node.state()) {
            case ready:
            case reserved:
            case failed:
            case inactive:
            case parked:
                storageMaintainer.syncLogs(context, true);
                removeContainerIfNeededUpdateContainerState(context, container);
                updateNodeRepoWithCurrentAttributes(context, Optional.empty());
                stopServicesIfNeeded(context);
                break;
            case active:
                storageMaintainer.syncLogs(context, true);
                storageMaintainer.cleanDiskIfFull(context);
                storageMaintainer.handleCoreDumpsForContainer(context, container, false);

                
                var runOrdinaryWireguardTasks = true;
                if (container.isPresent() && container.get().state().isRunning()) {
                    Optional<Container> finalContainer = container;
                    wireguardTasks.forEach(task -> task.converge(context, finalContainer.get().id()));
                    runOrdinaryWireguardTasks = false;
                }

                if (downloadImageIfNeeded(context, container)) {
                    context.log(logger, "Waiting for image to download " + context.node().wantedDockerImage().get().asString());
                    return;
                }
                dropDocsIfNeeded(context, container);
                container = removeContainerIfNeededUpdateContainerState(context, container);
                credentialsMaintainers.forEach(maintainer -> maintainer.converge(context));
                if (container.isEmpty()) {
                    containerState = STARTING;
                    container = Optional.of(startContainer(context));
                    containerState = UNKNOWN;
                    runOrdinaryWireguardTasks = true;
                } else {
                    container = Optional.of(updateContainerIfNeeded(context, container.get()));
                }

                aclMaintainer.ifPresent(maintainer -> maintainer.converge(context));
                if (runOrdinaryWireguardTasks) {
                    Optional<Container> finalContainer = container;
                    wireguardTasks.forEach(task -> task.converge(context, finalContainer.get().id()));
                }
                startServicesIfNeeded(context);
                resumeNodeIfNeeded(context);
                if (healthChecker.isPresent()) {
                    healthChecker.get().verifyHealth(context);
                    if (firstSuccessfulHealthCheckInstant.isEmpty())
                        firstSuccessfulHealthCheckInstant = Optional.of(clock.instant());

                    Duration timeLeft = Duration.between(clock.instant(), firstSuccessfulHealthCheckInstant.get().plus(warmUpDuration(context)));
                    if (!container.get().resources().equalsCpu(getContainerResources(context)))
                        throw ConvergenceException.ofTransient("Refusing to resume until warm up period ends (" +
                                (timeLeft.isNegative() ? "next tick" : "in " + timeLeft) + ")");
                }
                serviceDumper.processServiceDumpRequest(context);

                
                
                
                
                
                
                
                
                
                
                updateNodeRepoWithCurrentAttributes(context, container.map(Container::createdAt));
                if (suspendedInOrchestrator || node.orchestratorStatus().isSuspended()) {
                    context.log(logger, "Call resume against Orchestrator");
                    orchestrator.resume(context.hostname().value());
                    suspendedInOrchestrator = false;
                }
                break;
            case provisioned:
                nodeRepository.setNodeState(context.hostname().value(), NodeState.ready);
                break;
            case dirty:
                removeContainerIfNeededUpdateContainerState(context, container);
                context.log(logger, "State is " + node.state() + ", will delete application storage and mark node as ready");
                credentialsMaintainers.forEach(maintainer -> maintainer.clearCredentials(context));
                storageMaintainer.syncLogs(context, false);
                storageMaintainer.archiveNodeStorage(context);
                updateNodeRepoWithCurrentAttributes(context, Optional.empty());
                nodeRepository.setNodeState(context.hostname().value(), NodeState.ready);
                break;
            default:
                throw ConvergenceException.ofError("UNKNOWN STATE " + node.state().name());
        }
    }

Line commented on: Optional<Container> finalContainer = container;

Revised code:
void doConverge(NodeAgentContext context) {
        NodeSpec node = context.node();
        Optional<Container> container = getContainer(context);

        
        if (currentRebootGeneration < node.currentRebootGeneration())
            currentRebootGeneration = node.currentRebootGeneration();

        
        
        if (currentRestartGeneration.isPresent() != node.currentRestartGeneration().isPresent() ||
                currentRestartGeneration.map(current -> current < node.currentRestartGeneration().get()).orElse(false))
            currentRestartGeneration = node.currentRestartGeneration();

        if (!node.equals(lastNode)) {
            logChangesToNodeSpec(context, lastNode, node);
            lastNode = node;
        }

        switch (node.state()) {
            case ready:
            case reserved:
            case failed:
            case inactive:
            case parked:
                storageMaintainer.syncLogs(context, true);
                removeContainerIfNeededUpdateContainerState(context, container);
                updateNodeRepoWithCurrentAttributes(context, Optional.empty());
                stopServicesIfNeeded(context);
                break;
            case active:
                storageMaintainer.syncLogs(context, true);
                storageMaintainer.cleanDiskIfFull(context);
                storageMaintainer.handleCoreDumpsForContainer(context, container, false);

                
                var runOrdinaryWireguardTasks = true;
                if (container.isPresent() && container.get().state().isRunning()) {
                    Optional<Container> finalContainer = container;
                    wireguardTasks.forEach(task -> task.converge(context, finalContainer.get().id()));
                    runOrdinaryWireguardTasks = false;
                }

                if (downloadImageIfNeeded(context, container)) {
                    context.log(logger, "Waiting for image to download " + context.node().wantedDockerImage().get().asString());
                    return;
                }
                dropDocsIfNeeded(context, container);
                container = removeContainerIfNeededUpdateContainerState(context, container);
                credentialsMaintainers.forEach(maintainer -> maintainer.converge(context));
                if (container.isEmpty()) {
                    containerState = STARTING;
                    container = Optional.of(startContainer(context));
                    containerState = UNKNOWN;
                    runOrdinaryWireguardTasks = true;
                } else {
                    container = Optional.of(updateContainerIfNeeded(context, container.get()));
                }

                aclMaintainer.ifPresent(maintainer -> maintainer.converge(context));
                if (runOrdinaryWireguardTasks) {
                    Optional<Container> finalContainer = container;
                    wireguardTasks.forEach(task -> task.converge(context, finalContainer.get().id()));
                }
                startServicesIfNeeded(context);
                resumeNodeIfNeeded(context);
                if (healthChecker.isPresent()) {
                    healthChecker.get().verifyHealth(context);
                    if (firstSuccessfulHealthCheckInstant.isEmpty())
                        firstSuccessfulHealthCheckInstant = Optional.of(clock.instant());

                    Duration timeLeft = Duration.between(clock.instant(), firstSuccessfulHealthCheckInstant.get().plus(warmUpDuration(context)));
                    if (!container.get().resources().equalsCpu(getContainerResources(context)))
                        throw ConvergenceException.ofTransient("Refusing to resume until warm up period ends (" +
                                (timeLeft.isNegative() ? "next tick" : "in " + timeLeft) + ")");
                }
                serviceDumper.processServiceDumpRequest(context);

                
                
                
                
                
                
                
                
                
                
                updateNodeRepoWithCurrentAttributes(context, container.map(Container::createdAt));
                if (suspendedInOrchestrator || node.orchestratorStatus().isSuspended()) {
                    context.log(logger, "Call resume against Orchestrator");
                    orchestrator.resume(context.hostname().value());
                    suspendedInOrchestrator = false;
                }
                break;
            case provisioned:
                nodeRepository.setNodeState(context.hostname().value(), NodeState.ready);
                break;
            case dirty:
                removeContainerIfNeededUpdateContainerState(context, container);
                context.log(logger, "State is " + node.state() + ", will delete application storage and mark node as ready");
                credentialsMaintainers.forEach(maintainer -> maintainer.clearCredentials(context));
                storageMaintainer.syncLogs(context, false);
                storageMaintainer.archiveNodeStorage(context);
                updateNodeRepoWithCurrentAttributes(context, Optional.empty());
                nodeRepository.setNodeState(context.hostname().value(), NodeState.ready);
                break;
            default:
                throw ConvergenceException.ofError("UNKNOWN STATE " + node.state().name());
        }
    }