fix(agent-gateway): inject KB_AUTO_MCP_DISABLED on headless launch + durable job state#14
Merged
jorisjonkers-dev-agents[bot] merged 7 commits intoJul 10, 2026
Conversation
…durable job state Defect 1: HeadlessJobManager.DefaultProcessFactory now sets KB_AUTO_MCP_DISABLED=1 in the child process environment for every headless launch. Council/headless workers on hosted runners no longer fire auto-KB recall or capture hooks by accident. An explicit enableKbHooks=true field on HeadlessLaunchRequest and HeadlessRequest DTO lets individual runs opt back in. Defect 2: Job state is persisted to a JSON sidecar file (headless-<id>.json) in the gateway state dir on every status transition. InitializingBean.afterPropertiesSet reloads sidecar files at startup: completed/failed/cancelled jobs are restored as-is; any job still marked RUNNING is re-surfaced as FAILED because the underlying process cannot have survived the Pod restart. Defect 3 (RunnerPodChatGenerator/AgentGatewayClient alignment) is tracked separately as an agents-api change; this commit does not touch agents-api. Fixes #11
…ss fixes Fix ktlint style violations in HeadlessJobManager (chain newline) and HeadlessJobSidecar (multiline when branches, buildString newline) flagged by the CI lint pass. Restructure HeadlessJobSidecar.readString to avoid the ComplexMethod suppression by extracting a unescape helper. Fix a timing race in HeadlessJobManagerTest: waitUntil(status==FAILED) could see the status update before the SPAWN/FAILURE telemetry event was recorded. Add a secondary waitUntil for the telemetry event before asserting.
Close the Files.list directory stream with use{} to avoid leaking a
file descriptor on every startup reload. Persist the recovered FAILED
sidecar back to disk so a RUNNING->FAILED recovery converges instead
of being re-applied with a fresh completedAt on every restart. Widen
the sidecar filename pattern to accept uppercase hex. Replace the
DefaultProcessFactory KB test with assertions that actually launch
through the factory and verify the injected (or absent) variable in
the child process environment.
…decar write race shutdownNow interrupts in-flight job threads whose interrupt path persists a final sidecar state file. Without awaiting termination the write can race external cleanup of the state directory (observed as a JUnit TempDir deletion failure in CI). destroy now waits up to five seconds for job threads to finish their final transition.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #11
Summary
Three defects in the headless launch path, two fixed in this PR:
Defect 1 — KB_AUTO_MCP_DISABLED not injected on headless/council launch
HeadlessJobManager.DefaultProcessFactorynow setsKB_AUTO_MCP_DISABLED=1in the child process environment for every headless launch. Council and headless workers running on hosted runners can no longer accidentally fire auto-KB recall or capture hooks. A newenableKbHooks: Boolean = falsefield onHeadlessLaunchRequestandHeadlessRequest(DTO) allows individual runs to opt back in explicitly.Defect 2 — Headless job state is in-memory only
Job metadata is now persisted as a JSON sidecar file (
headless-<id>.json) in the gateway state dir on every status transition (RUNNING → COMPLETED/FAILED/CANCELLED).HeadlessJobManagerimplementsInitializingBean;afterPropertiesSetreloads sidecar files at startup so callers can still read final status and output of jobs that completed before the current Pod started. Jobs still marked RUNNING in a sidecar (process died mid-run) are re-surfaced as FAILED.The sidecar format is a minimal hand-rolled JSON writer/reader with no new dependencies. A dedicated
HeadlessJobSidecarTestcovers round-trip for all status variants plus the idempotent overwrite.Defect 3 — RunnerPodChatGenerator bypasses AgentGatewayClient (out of scope)
RunnerPodChatGeneratorand the alignment withAgentGatewayClient.startHeadlessJob()live in agents-api, not agent-runtime. That fix is tracked separately; this PR does not touch agents-api. TheagentKindtyping concern (untyped string →WorkspaceAgentKindenum) is already resolved in agents-api viaChatGenerationProperties.runnerPodAgentKind; the remaining concern is routing through the shared client, which is an agents-api concern.Boundary note — agents-api #14
Defect 2 (durable state) pairs with agents-api #14 (reconciliation). This PR covers the gateway-side sidecar persistence as specified in this issue. Coordinating the reconciliation handshake between agents-api and the gateway is left to agents-api #14.