Repository navigation
fix(controller): make FUSE model-cache staging safe across stagers and serving pods - #2276
Merged
Defilan merged 6 commits intoOct 27, 2026
Merged
Conversation
…ownloader The remedy for a refused FUSE staging was written twice: once in the init script, which already chooses between the prefetch and the s3:// wording, and again in the ModelTransferHealthy signature, which combined both in different words. A change to prefetch support would have to update both or the pod log and the condition would disagree. The remedies are now one constant per source kind. The script prints the one for its source, and the diagnosis takes the remedy from the termination message, falling back to a pointer at the log when the tail lost it. Fixes defilantech#2251 Signed-off-by: Christopher Maher <chris@mahercode.io>
…SE cache defilantech#2185 stopped serving pods from staging multi-file models on a FUSE cache, where flock does not exclude across nodes, but the single-file path still took cacheDirLock on any filesystem. On a BlobFuse RWX claim two pods on different nodes could both hold it and curl -C - into the same partial, the truncated-file race of defilantech#2158. FUSE detection now sits next to cacheDirLock in one prologue that both builders open with. A warm cache stays usable, and a serving pod on FUSE takes no lock, sweeps nothing and refuses any transfer with the same ModelCacheLockUnsupported message and condition, with a remedy for its source kind (local sources get their own). The single-file downloader now carries LLMKUBE_PREFETCH_STAGER=false like the multi-file one, so a single-file prefetch Job is a stager: it may stage on FUSE, waits for a failed pod before replacing it and is deleted in the foreground. Fixes defilantech#2254 Signed-off-by: Christopher Maher <chris@mahercode.io>
…hed copy When the upstream changed and a serving pod on a FUSE cache kept its copy, the multi-file init logged a ModelCacheLockUnsupported error followed by "Revalidation unreachable ... kept cached copy" and exited 0. The behavior was right, but the log read as two failures, and "unreachable" was wrong because the origin had answered. A serving pod on FUSE now decides before trying to stage: it keeps a copy that passes the local checks and says whether the origin changed or did not answer, or refuses when there is nothing it may keep. Refs defilantech#2255 Signed-off-by: Christopher Maher <chris@mahercode.io>
…e record A FUSE cache staged before defilantech#2185 has no .llmkube-size record, and only pods off FUSE backfilled one, so such a cache warned "no valid size record" on every start for good. The prefetch stager is the one pod allowed to write a FUSE cache, so its IfNotPresent pass now records the cached file's size as pods on other filesystems do. Serving pods on FUSE still write nothing. Refs defilantech#2255 Signed-off-by: Christopher Maher <chris@mahercode.io>
llmkube_atomic_write writes size records, checksum stamps and rejection markers through a mktemp file and a rename. A pod that died between the two left the temp file on the claim for good, because the cache sweeps only delete *.tmp, and a write that failed did not remove its own temp file. The temp file is now <dest>.llmkube-tmp.XXXXXX, a name no artifact has, and a failed write removes it. Every downloader that may write the cache sweeps such files, and the two unambiguous older names, once they are over ten minutes old: a serving pod on FUSE writes stamps without the directory lock, so a younger one may be a write in flight. The older <file>.sha256.XXXXXX name is not swept, since a repository can ship a file that matches it. Refs defilantech#2255 Signed-off-by: Christopher Maher <chris@mahercode.io>
…y and claim The cache directory is keyed on the source alone, and on a FUSE claim a prefetch stager writes it without flock. Two Models on the same source with prefetch on one BlobFuse RWX claim each got a Job, and both curl -C - into the same partials, the truncated-partial race of defilantech#2158 across Jobs. Foreground deletion and podReplacementPolicy only order pods within one Job. The Model controller now creates a prefetch Job only while no other prefetch Job, or pod left from one, that writes the same cache directory on the same claim is still active. The target and the activity are read from the Job's pod template and status, so Jobs from an older operator count too, and the reads bypass the cache. The check and the create are one step across the controller's workers. A held Model keeps its entry Pending, reports PrefetchWaiting naming the Job and Model it waits for, and checks again every 15 seconds; the second stager then finds a warm cache. Serializing rather than refusing keeps both Models working without user action. Fixes defilantech#2250 Signed-off-by: Christopher Maher <chris@mahercode.io>
Defilan
force-pushed
the
fix/model-cache-fuse-staging-2250
branch
from
October 27, 2026 18:29
3c8a807 to
794ea09
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Merged
6 of 7 tasks
eleboucher
pushed a commit
to eleboucher/homelab
that referenced
this pull request
Oct 31, 2026
…0.10.15) (#2331) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [ghcr.io/defilantech/charts/llmkube](https://github.com/defilantech/LLMKube) | HelmChart | patch | `0.10.2` → `0.10.15` | --- >⚠️ **Warning** > > Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/567) for more information. --- ### Release Notes <details> <summary>defilantech/LLMKube (ghcr.io/defilantech/charts/llmkube)</summary> ### [`v0.10.15`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#01015-2026-10-31) [Compare Source](defilantech/LLMKube@v0.10.14...v0.10.15) ##### Features - **agent:** add --engine-env-passthrough to pass named variables to Metal engines ([6d4fba0](defilantech/LLMKube@6d4fba0)) - **agent:** give Metal engines an allowlisted environment (fixes [#​2314](defilantech/LLMKube#2314)) ([6d4fba0](defilantech/LLMKube@6d4fba0)) - **foreman:** select the forge provider by name, remote host, or default ([#​2292](defilantech/LLMKube#2292)) ([239411a](defilantech/LLMKube@239411a)) - **foreman:** stream in-turn generation progress ([#​2313](defilantech/LLMKube#2313)) ([3d57743](defilantech/LLMKube@3d57743)) - **metal-agent:** read only marked Secrets through sourceSecretRef (fixes [#​1956](defilantech/LLMKube#1956)) ([eaecad3](defilantech/LLMKube@eaecad3)) - **metal:** limit the metal-agent's Service and EndpointSlice writes by admission policy ([#​2319](defilantech/LLMKube#2319)) ([a8ea5bf](defilantech/LLMKube@a8ea5bf)) - **release:** publish a Homebrew cask for the metal-agent ([#​2234](defilantech/LLMKube#2234)) ([1b29497](defilantech/LLMKube@1b29497)) - **router:** mirror requests to the other backends of a shadow rule (fixes [#​2327](defilantech/LLMKube#2327)) ([40266ab](defilantech/LLMKube@40266ab)) ##### Bug Fixes - **agent:** pin the exact powermetrics argument vector in sudoers ([d28c55f](defilantech/LLMKube@d28c55f)) - **controller:** treat a ModelPool resident removed from spec.members as gone ([#​2310](defilantech/LLMKube#2310)) ([87464ad](defilantech/LLMKube@87464ad)) - **foreman:** bound the Metal engine port read from the agent's EndpointSlice ([#​2321](defilantech/LLMKube#2321)) ([75837e3](defilantech/LLMKube@75837e3)) - **metal-agent:** re-check a refused InferenceService on a backoff (fixes [#​2329](defilantech/LLMKube#2329)) ([6f65b30](defilantech/LLMKube@6f65b30)) - **metal-agent:** re-issue an ingress certificate the Mac's clock no longer accepts ([7e7fbaa](defilantech/LLMKube@7e7fbaa)) - **metal-agent:** read sourceSecretRef from the Model's namespace ([eaecad3](defilantech/LLMKube@eaecad3)) - **metal-agent:** retry a start that hit a transient source Secret read error ([5e13d5c](defilantech/LLMKube@5e13d5c)) - **metal-agent:** retry a transient remote size probe failure without refusing (fixes [#​2326](defilantech/LLMKube#2326)) ([5e13d5c](defilantech/LLMKube@5e13d5c)) - **metal:** bind MetalNode Reachable to the Mac with a UID-named certificate (refs [#​2265](defilantech/LLMKube#2265)) ([7e7fbaa](defilantech/LLMKube@7e7fbaa)) - **metal:** expire a MetalNode Reachable result no check has renewed (refs [#​2265](defilantech/LLMKube#2265)) ([7e7fbaa](defilantech/LLMKube@7e7fbaa)) - **metal:** read MetalNode verifier finish times on the controller's clock (refs [#​2265](defilantech/LLMKube#2265)) ([7e7fbaa](defilantech/LLMKube@7e7fbaa)) - **metal:** trust only the reported certificate in the MetalNode dial-back ([7e7fbaa](defilantech/LLMKube@7e7fbaa)) - preserve Foreman audit and transcript records per attempt ([#​2311](defilantech/LLMKube#2311)) ([3e838f9](defilantech/LLMKube@3e838f9)) - **router:** dispatch only to backends with a rule's required capabilities (fixes [#​2328](defilantech/LLMKube#2328)) ([e533192](defilantech/LLMKube@e533192)) - **router:** honor the weighted rule strategy on the Proxy data plane (fixes [#​2325](defilantech/LLMKube#2325)) ([7b34a43](defilantech/LLMKube@7b34a43)) ##### Documentation - **macos:** explain why Login Items lists the agent as Defilan Technologies LLC ([#​2307](defilantech/LLMKube#2307)) ([5b5e17e](defilantech/LLMKube@5b5e17e)) - move Foreman stream guide before references ([#​2322](defilantech/LLMKube#2322)) ([d856cb1](defilantech/LLMKube@d856cb1)) - **upgrade:** a MetalNode is Reachable only when the Mac's metal-agent reports an ingress certificate naming its MetalNode. After upgrading the controller, every Mac shows Reachable=False with reason AgentUpgradeRequired, and its hostIP is cleared, until its metal-agent is upgraded too; upgrade the agents promptly. Nothing routes to hostIP yet, so serving is unaffected. The dial-back verifier image's curl must be 7.57 or later with a TLS library that accepts a self-signed certificate as its own trust anchor; the default curlimages/curl image does. ([7e7fbaa](defilantech/LLMKube@7e7fbaa)) - **upgrade:** Metal engines now inherit only PATH, HOME, USER, LOGNAME, TMPDIR, LANG, TZ, LC\_\*, HF_HOME and HF_HUB_CACHE from the agent's environment, plus the variables the agent sets for each runtime. If an engine relies on another variable from the agent's launchd environment (for example a GGML or MLX tuning variable, or proxy settings for llama-server's own `-hf` download), list it in `--engine-env-passthrough`. Engines adopted from a previous agent process keep their old environment until they restart; run `llmkube-metal-agent stop-engines` after the bootout to apply it at once. ([6d4fba0](defilantech/LLMKube@6d4fba0)) - **upgrade:** on the Proxy data plane, a ModelRouter rule with match.requiredCapabilities now sends requests only to the backends that advertise all of them, under every strategy. A primary-fallback rule no longer sends to, or falls back to, a backend that lacks them; when every capable backend fails, the request fails instead of landing on an incapable one. ([e533192](defilantech/LLMKube@e533192)) - **upgrade:** on the Proxy data plane, ModelRouter rules with strategy: shadow now send a copy of each request to the rule's other backends, including external ones, which bill those requests. A shadow rule with one backend now fails validation, and one that mirrors to a ModelPool member fails the compile and keeps the previous config. ([40266ab](defilantech/LLMKube@40266ab)) - **upgrade:** on the Proxy data plane, ModelRouter rules with strategy: weighted now split requests by backend weight instead of sending all of them to the first backend. weight: 0 drains a backend, matching the Gateway data plane. A weighted rule whose backends cannot take traffic now fails validation, and a weighted rule across two members of one ModelPool fails the compile and keeps the previous config. ([7b34a43](defilantech/LLMKube@7b34a43)) - **upgrade:** the Metal agent now reads a Model's spec.sourceSecretRef only when the Secret is labeled inference.llmkube.dev/model-source-credentials=true; otherwise the InferenceService is refused with SourceSecretNotAllowed. Before upgrading the agent, label each credentials Secret your Metal Models use: `kubectl label secret <name> -n <namespace> inference.llmkube.dev/model-source-credentials=true`. For one release, `--allow-unlabeled-source-secrets` keeps the old behavior with a warning; it is deprecated. A Hugging Face source whose Secret cannot be read is now refused instead of downloading anonymously. ([eaecad3](defilantech/LLMKube@eaecad3)) - **upgrade:** the powermetrics sudoers rule now names the exact command line the agent runs, with the sampling interval rendered in. Upgrading the agent does not change an installed /etc/sudoers.d/llmkube-powermetrics: on hosts that installed it, re-run `make install-powermetrics-sudo` (with `APPLE_POWER_INTERVAL_MS=<ms>` if the agent uses a non-default `--apple-power-interval`), then check with `sudo -ln | grep powermetrics` that the rule ends in `-i` followed by a number. ([d28c55f](defilantech/LLMKube@d28c55f)) ### [`v0.10.14`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#01014-2026-10-29) [Compare Source](defilantech/LLMKube@v0.10.13...v0.10.14) ##### Features - **cli:** send the endpoint API key from llmkube benchmark ([#​2297](defilantech/LLMKube#2297)) ([df2e008](defilantech/LLMKube@df2e008)) - **router:** add spec.proxy.drainTimeout for the router-proxy shutdown ([#​2304](defilantech/LLMKube#2304)) ([113e009](defilantech/LLMKube@113e009)) - **router:** opt-in client address and caller header on the audit log ([#​2288](defilantech/LLMKube#2288)) ([4d1faac](defilantech/LLMKube@4d1faac)) ##### Bug Fixes - **controller:** keep a ModelPool resident the router re-activates during a reclaim ([#​2290](defilantech/LLMKube#2290)) ([857daf2](defilantech/LLMKube@857daf2)) - **controller:** remove a key dropped from podLabels or podAnnotations from the pods ([#​2289](defilantech/LLMKube#2289)) ([ca5df08](defilantech/LLMKube@ca5df08)) - **foreman:** route the remaining GitHub-only paths through the forge seams ([#​2291](defilantech/LLMKube#2291)) ([a333270](defilantech/LLMKube@a333270)) - **metrics:** each binary serves only the metrics it records ([#​2296](defilantech/LLMKube#2296)) ([de8ca21](defilantech/LLMKube@de8ca21)) ##### Documentation - **modelpool:** leave member replicas out of GitOps manifests ([#​2300](defilantech/LLMKube#2300)) ([bcbc357](defilantech/LLMKube@bcbc357)) ### [`v0.10.13`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#01013-2026-10-28) [Compare Source](defilantech/LLMKube@v0.10.12...v0.10.13) ##### Features - **agent:** add the llmkube-metal-agent stop-engines command ([2cd2ec9](defilantech/LLMKube@2cd2ec9)) - **agent:** keep Metal engines serving across metal-agent restarts and adopt them on startup (refs [#​2079](defilantech/LLMKube#2079)) ([2cd2ec9](defilantech/LLMKube@2cd2ec9)) - **release:** sign and notarize the macOS release binaries ([#​2233](defilantech/LLMKube#2233)) ([f5ff962](defilantech/LLMKube@f5ff962)) - **router:** podLabels and podAnnotations for router-proxy pods ([#​2285](defilantech/LLMKube#2285)) ([a736e18](defilantech/LLMKube@a736e18)) - **router:** publish per-backend modalities and context length on /v1/models ([#​2249](defilantech/LLMKube#2249)) ([2887f54](defilantech/LLMKube@2887f54)) ##### Bug Fixes - apply CRDs server-side in make install and make deploy ([#​2275](defilantech/LLMKube#2275)) ([edaa4f7](defilantech/LLMKube@edaa4f7)) - **chart:** leave --init-container-user off when its value is unset ([#​2286](defilantech/LLMKube#2286)) ([ac541db](defilantech/LLMKube@ac541db)) - **cli:** pin only single-writer claims and make the cache pod image configurable ([#​2178](defilantech/LLMKube#2178)) ([2fe250b](defilantech/LLMKube@2fe250b)) - **controller:** annotate router-proxy pods for scraping under --emit-scrape-annotations ([#​2268](defilantech/LLMKube#2268)) ([07fb7f4](defilantech/LLMKube@07fb7f4)) - **controller:** chown the cache root to the init container's uid when fsGroup is off ([#​2273](defilantech/LLMKube#2273)) ([c9d86ad](defilantech/LLMKube@c9d86ad)) - **controller:** create no HPA for multiNode services ([#​2272](defilantech/LLMKube#2272)) ([c8d6f76](defilantech/LLMKube@c8d6f76)) - **controller:** delete FUSE stager Jobs in the foreground without the feature-gated field ([#​2269](defilantech/LLMKube#2269)) ([e439f60](defilantech/LLMKube@e439f60)) - **controller:** make FUSE model-cache staging safe across stagers and serving pods ([#​2276](defilantech/LLMKube#2276)) ([6c7c1fe](defilantech/LLMKube@6c7c1fe)) - **controller:** point the router-proxy Service at the port the proxy listens on ([#​2280](defilantech/LLMKube#2280)) ([1c69118](defilantech/LLMKube@1c69118)) - **controller:** run the stall-probe tests on a fake clock ([#​2267](defilantech/LLMKube#2267)) ([661856a](defilantech/LLMKube@661856a)) - **router:** tell client cancellations, upstream errors and timeouts apart ([#​2284](defilantech/LLMKube#2284)) ([3a2ea74](defilantech/LLMKube@3a2ea74)) - use vLLM's real TurboQuant KV cache types in the sample and docs ([#​2270](defilantech/LLMKube#2270)) ([3b4ffb6](defilantech/LLMKube@3b4ffb6)) ##### Documentation - **upgrade:** metal-agent engines now keep running when the agent stops and the next agent adopts them. To roll back to an older agent, run `launchctl bootout gui/$(id -u)/com.llmkube.metal-agent` and then `llmkube-metal-agent stop-engines` with the current binary before installing the older one, or every model is loaded twice. `make uninstall-metal-agent` stops the engines for you. Adopted engines keep the flags they started with; run stop-engines after the bootout to apply new defaults. ([2cd2ec9](defilantech/LLMKube@2cd2ec9)) ### [`v0.10.12`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#01012-2026-10-27) [Compare Source](defilantech/LLMKube@v0.10.11...v0.10.12) ##### Features - **api:** add MetalNode, verified by a controller dial-back, with the agent reporting through its Lease ([#​2235](defilantech/LLMKube#2235)) ([fccc1bc](defilantech/LLMKube@fccc1bc)) - **cli:** add llmkube metal join and leave, with agent token renewal ([#​2246](defilantech/LLMKube#2246)) ([b1f6602](defilantech/LLMKube@b1f6602)) - **cli:** add llmkube metal token create and metal remove ([#​2236](defilantech/LLMKube#2236)) ([f54414a](defilantech/LLMKube@f54414a)) ##### Bug Fixes - **controller:** keep a ModelPool activation while its member is held at zero ([#​2241](defilantech/LLMKube#2241)) ([8fc4143](defilantech/LLMKube@8fc4143)) - **controller:** map sglangConfig.enablePrefixCaching onto --disable-radix-cache ([#​2259](defilantech/LLMKube#2259)) ([d499aa4](defilantech/LLMKube@d499aa4)) - **controller:** stage under the cache lock when the init image's stat has no -f ([#​2260](defilantech/LLMKube#2260)) ([52241de](defilantech/LLMKube@52241de)) - **router:** list each backend on /v1/models under the id BackendNameMatch routes ([#​2257](defilantech/LLMKube#2257)) ([4627cfc](defilantech/LLMKube@4627cfc)) - **router:** report moves off a quarantined pod as reason="quarantined" instead of reason="not_ready" ([faa7a5f](defilantech/LLMKube@faa7a5f)) - **router:** rewrite vLLM and SGLang backends to the name they serve ([#​2258](defilantech/LLMKube#2258)) ([3d39111](defilantech/LLMKube@3d39111)) - validate multi-file cache staging on shared volumes ([#​2185](defilantech/LLMKube#2185)) ([e6eab85](defilantech/LLMKube@e6eab85)) ### [`v0.10.11`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#01011-2026-10-25) [Compare Source](defilantech/LLMKube@v0.10.10...v0.10.11) ##### Features - **api:** accept fp8, float16 and bfloat16 in vllmConfig.kvCacheDtype ([#​2227](defilantech/LLMKube#2227)) ([31eb943](defilantech/LLMKube@31eb943)) - **api:** add spec.imagePullPolicy to InferenceService ([#​2208](defilantech/LLMKube#2208)) ([ec54d28](defilantech/LLMKube@ec54d28)) - **controller:** move the SGLang defaults to v0.5.22 and report removed attention backends ([#​2221](defilantech/LLMKube#2221)) ([33f9bb1](defilantech/LLMKube@33f9bb1)) - **controller:** move the vLLM default to v0.32.0 and check every flag against it ([#​2223](defilantech/LLMKube#2223)) ([0144a4c](defilantech/LLMKube@0144a4c)) - **controller:** run every llama.cpp default from one pinned build, b11854 ([#​2220](defilantech/LLMKube#2220)) ([052840e](defilantech/LLMKube@052840e)) - **router:** weigh LoadAware placement by estimated prefill tokens in flight ([#​2193](defilantech/LLMKube#2193)) ([a33735c](defilantech/LLMKube@a33735c)) ##### Bug Fixes - **controller:** render vllmConfig.speculative as --speculative-config ([#​2210](defilantech/LLMKube#2210)) ([191dcbd](defilantech/LLMKube@191dcbd)) - **controller:** report sglangConfig tool-call parsers SGLang does not register ([#​2228](defilantech/LLMKube#2228)) ([90fed2e](defilantech/LLMKube@90fed2e)) ### [`v0.10.10`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#01010-2026-10-24) [Compare Source](defilantech/LLMKube@v0.10.9...v0.10.10) ##### Features - **controller:** add --model-cache-prep to skip the root cache prep ([#​2206](defilantech/LLMKube#2206)) ([8bcb973](defilantech/LLMKube@8bcb973)) - **router:** compile dataPlane: AgentGateway to AgentgatewayModel ([#​2162](defilantech/LLMKube#2162)) ([26b1ef4](defilantech/LLMKube@26b1ef4)) ##### Bug Fixes - **controller:** report a prefetch as downloading while its downloader runs ([#​2207](defilantech/LLMKube#2207)) ([7699514](defilantech/LLMKube@7699514)) - **router:** let every waiter of a failed ModelPool swap see its outcome ([#​2203](defilantech/LLMKube#2203)) ([b95db62](defilantech/LLMKube@b95db62)) ### [`v0.10.9`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#0109-2026-10-23) [Compare Source](defilantech/LLMKube@v0.10.8...v0.10.9) ##### Features - **api:** affinity and topology spread for the router proxy, rolling without surge under hard placement ([#​2200](defilantech/LLMKube#2200)) ([3a61700](defilantech/LLMKube@3a61700)) - **router:** proxy the Anthropic Messages API like chat completions ([#​2201](defilantech/LLMKube#2201)) ([86223aa](defilantech/LLMKube@86223aa)) ##### Bug Fixes - **router:** retry stale keep-alive connections and quarantine a pod only after two failures ([#​2197](defilantech/LLMKube#2197)) ([b279053](defilantech/LLMKube@b279053)) ### [`v0.10.8`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#0108-2026-10-23) [Compare Source](defilantech/LLMKube@v0.10.7...v0.10.8) ##### Features - **api:** type the vLLM tool-call and reasoning parsers and admit GLM on SGLang ([#​2168](defilantech/LLMKube#2168)) ([fd64c72](defilantech/LLMKube@fd64c72)) - **controller:** add InferenceService spec.hubOffline for serving pods ([#​2188](defilantech/LLMKube#2188)) ([a911cb2](defilantech/LLMKube@a911cb2)) - **controller:** keep 3 old ReplicaSets for LLMKube-managed Deployments by default ([#​2182](defilantech/LLMKube#2182)) ([5e1722f](defilantech/LLMKube@5e1722f)) - **router:** honour endpoint nodePort and externalTrafficPolicy, add proxy runtimeClassName ([#​2183](defilantech/LLMKube#2183)) ([a8f9e57](defilantech/LLMKube@a8f9e57)) - **router:** on pools under 3 pods, move a session only when its pod is KV-full ([#​2192](defilantech/LLMKube#2192)) ([f9b934c](defilantech/LLMKube@f9b934c)) - **router:** remember LoadAware sessions and move them only under real pressure ([#​2180](defilantech/LLMKube#2180)) ([1e8ce5a](defilantech/LLMKube@1e8ce5a)) ##### Bug Fixes - **router:** answer a ModelPool swap past swapBudget with 503 and Retry-After ([#​2181](defilantech/LLMKube#2181)) ([7c0d84e](defilantech/LLMKube@7c0d84e)) - **router:** release request bodies once sent and raise the proxy's default memory limit ([#​2196](defilantech/LLMKube#2196)) ([140fd6b](defilantech/LLMKube@140fd6b)) ### [`v0.10.7`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#0107-2026-10-23) [Compare Source](defilantech/LLMKube@v0.10.6...v0.10.7) ##### Features - **chart:** install the metal-agent RBAC from the Helm chart ([#​2165](defilantech/LLMKube#2165)) ([521e502](defilantech/LLMKube@521e502)) - **controller:** roll a multi-replica GPU service one pod at a time ([#​2164](defilantech/LLMKube#2164)) ([c4073cf](defilantech/LLMKube@c4073cf)) - **router:** load-aware, session-sticky placement for endpoint backends ([#​2166](defilantech/LLMKube#2166)) ([74cfb0e](defilantech/LLMKube@74cfb0e)) - **router:** the router proxy tracks endpoint backends' pods itself ([#​2159](defilantech/LLMKube#2159)) ([57070e1](defilantech/LLMKube@57070e1)) ### [`v0.10.6`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#0106-2026-10-22) [Compare Source](defilantech/LLMKube@v0.10.5...v0.10.6) ##### Features - **controller:** prefetch per cache claim, gated by the InferenceService ([#​2138](defilantech/LLMKube#2138)) ([d76f398](defilantech/LLMKube@d76f398)) - **router:** per-backend Endpoint Picker for dataPlane: AgentGateway ([#​2157](defilantech/LLMKube#2157)) ([c1bbe28](defilantech/LLMKube@c1bbe28)) ##### Bug Fixes - **cli:** read the model cache from its own pod in cache list ([#​2154](defilantech/LLMKube#2154)) ([996abe9](defilantech/LLMKube@996abe9)) - **controller:** refuse to repoint a same-name Service ([#​2149](defilantech/LLMKube#2149)) ([7965a1b](defilantech/LLMKube@7965a1b)) - **hf-listing:** read a tree size only when it is a whole number of bytes ([#​2153](defilantech/LLMKube#2153)) ([6e6723d](defilantech/LLMKube@6e6723d)) - **model:** report the staged total instead of status.size "0" ([#​2150](defilantech/LLMKube#2150)) ([f6710e7](defilantech/LLMKube@f6710e7)) ### [`v0.10.5`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#0105-2026-10-21) [Compare Source](defilantech/LLMKube@v0.10.4...v0.10.5) ##### Features - add make gate and make test-affected, a cached parallel round gate ([#​2106](defilantech/LLMKube#2106)) ([e971675](defilantech/LLMKube@e971675)) - **agent:** admit Metal models against memory already committed to running engines (closes [#​2080](defilantech/LLMKube#2080)) ([d2d2d43](defilantech/LLMKube@d2d2d43)) - **agent:** record each engine the metal-agent starts in the state directory (refs [#​2079](defilantech/LLMKube#2079)) ([0224d51](defilantech/LLMKube@0224d51)) - **controller:** add spec.startupTimeout for a bigger startup probe budget ([#​2129](defilantech/LLMKube#2129)) ([df0e9cd](defilantech/LLMKube@df0e9cd)) - **controller:** set fsGroupChangePolicy OnRootMismatch with the default fsGroup (closes [#​2058](defilantech/LLMKube#2058)) ([2bd4538](defilantech/LLMKube@2bd4538)) ##### Bug Fixes - **agent:** escalate to SIGKILL when stopping an engine the agent did not spawn ([0224d51](defilantech/LLMKube@0224d51)) - **agent:** keep the pressure block when an eviction teardown completed ([#​2107](defilantech/LLMKube#2107)) ([fd9ab77](defilantech/LLMKube@fd9ab77)) - **agent:** replace a hung oMLX daemon instead of starting a second one ([#​2105](defilantech/LLMKube#2105)) ([a16c348](defilantech/LLMKube@a16c348)) - **agent:** restart services evicted under memory pressure once memory recovers ([#​2093](defilantech/LLMKube#2093)) ([3db0ecc](defilantech/LLMKube@3db0ecc)) - answer 400 for request bodies that are not valid JSON ([#​2075](defilantech/LLMKube#2075)) ([d9826ff](defilantech/LLMKube@d9826ff)) - **chart:** fail fast on shared cache without default storageclass and support existingClaim ([#​2016](defilantech/LLMKube#2016)) ([#​2114](defilantech/LLMKube#2114)) ([c4f7f3d](defilantech/LLMKube@c4f7f3d)) - **chart:** gate llama.cpp InferenceAdmissionStalled on decode progress ([#​2065](defilantech/LLMKube#2065)) ([5b2f45d](defilantech/LLMKube@5b2f45d)) - **cli:** make cache clear and delete --purge-cache remove entries ([#​2134](defilantech/LLMKube#2134)) ([2b668e2](defilantech/LLMKube@2b668e2)) - **controller:** keep downloader credentials off curl's command line ([#​2098](defilantech/LLMKube#2098)) ([2207c2e](defilantech/LLMKube@2207c2e)) - **controller:** mount a memory-backed /dev/shm for multi-process vLLM, SGLang and TGI (closes [#​2099](defilantech/LLMKube#2099)) ([a68c98f](defilantech/LLMKube@a68c98f)) - **controller:** refuse to overwrite or recreate a same-name Deployment ([#​2096](defilantech/LLMKube#2096)) ([b90c8aa](defilantech/LLMKube@b90c8aa)) - **model:** canonicalize HF repo IDs so a trailing slash stages ([#​2128](defilantech/LLMKube#2128)) ([9289ac6](defilantech/LLMKube@9289ac6)) - **modelpool:** stop swap thrash on reversals, idle-probe blindness, and abandoned loads ([#​2130](defilantech/LLMKube#2130)) ([#​2135](defilantech/LLMKube#2135)) ([e7dee43](defilantech/LLMKube@e7dee43)) - **model:** serialize downloaders that share a cache directory ([#​2115](defilantech/LLMKube#2115)) ([13eca01](defilantech/LLMKube@13eca01)) - **sglang:** keep endpoint API keys out of process arguments ([#​2122](defilantech/LLMKube#2122)) ([7fdae50](defilantech/LLMKube@7fdae50)) - size metal-agent KV cache estimate from GQA attention shape ([#​2102](defilantech/LLMKube#2102)) ([a119234](defilantech/LLMKube@a119234)) ##### Documentation - cover per-request balancing in the ModelRouter page ([#​2095](defilantech/LLMKube#2095)) ([9ec4766](defilantech/LLMKube@9ec4766)) - **model-cache:** correct the CephFS fsGroupPolicy claim and the PSA advice ([2bd4538](defilantech/LLMKube@2bd4538)) - state differentiation, audience, and project status up front ([#​2100](defilantech/LLMKube#2100)) ([ee27e20](defilantech/LLMKube@ee27e20)) - **upgrade:** every InferenceService that uses the default pod security context rolls once on upgrade, because the generated pod template gains `fsGroupChangePolicy: OnRootMismatch` (a full model reload for large models) ([2bd4538](defilantech/LLMKube@2bd4538)) - **upgrade:** single-node vLLM, SGLang and TGI services with more than one GPU (or a tensor, pipeline or data-parallel size above 1) that do not mount /dev/shm themselves roll once on upgrade, because the generated pod template gains a memory-backed /dev/shm volume ([a68c98f](defilantech/LLMKube@a68c98f)) - **upgrade:** the metal-agent now admits a model only if it fits in the Mac's budget minus the memory committed to models already running, so a Mac whose models add up to more than its budget refuses the extra ones; a Model memoryBudget or memoryFraction above the Mac's budget is clamped to it unless the agent runs with --allow-model-memory-budget-override ([d2d2d43](defilantech/LLMKube@d2d2d43)) - **upgrade:** the metal-agent now writes a record per engine under --state-dir/engines (both relay and legacy mode) and fails an engine start when it cannot write it; make sure the state directory (default \~/Library/Application Support/llmkube/metal-agent) is writable by the agent's user ([0224d51](defilantech/LLMKube@0224d51)) ### [`v0.10.4`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#0104-2026-10-16) [Compare Source](defilantech/LLMKube@v0.10.3...v0.10.4) ##### Features - **agent:** cap the bytes a single Model download may write ([#​2088](defilantech/LLMKube#2088)) ([3852411](defilantech/LLMKube@3852411)) - **api:** endpoint API key and externalTrafficPolicy for InferenceService ([#​2043](defilantech/LLMKube#2043)) ([27a9214](defilantech/LLMKube@27a9214)) - **controller:** detect a stalled watch path with a lease canary, bounded reconciles and stall alerts ([#​2072](defilantech/LLMKube#2072)) ([d00e0cf](defilantech/LLMKube@d00e0cf)) - **controller:** detect keyed pool siblings and vLLM env-var keys in ModelRouter ([#​2068](defilantech/LLMKube#2068)) ([78889f0](defilantech/LLMKube@78889f0)) - **controller:** detect ModelRouter backends keyed through --api-key on the command line ([#​2063](defilantech/LLMKube#2063)) ([3674acc](defilantech/LLMKube@3674acc)) - **controller:** stage HF mirror repos with spec.files and expand globs from the repo listing ([#​2071](defilantech/LLMKube#2071)) ([9e5d7d3](defilantech/LLMKube@9e5d7d3)) ##### Bug Fixes - **agent:** health restarts stop the unhealthy engine first, wait for repeated failures, and back off ([#​2090](defilantech/LLMKube#2090)) ([407e02e](defilantech/LLMKube@407e02e)) - **agent:** keep a Metal service running when its Model lookup fails transiently ([#​2089](defilantech/LLMKube#2089)) ([e22eeab](defilantech/LLMKube@e22eeab)) - **controller:** merge DRA pod scheduling fields and reject multiNode with resourceClaims ([#​2062](defilantech/LLMKube#2062)) ([9319745](defilantech/LLMKube@9319745)) - no device-plugin GPU limit when a Model uses DRA resourceClaims ([#​2060](defilantech/LLMKube#2060)) ([8c3e434](defilantech/LLMKube@8c3e434)) ##### Documentation - APISIX in front of LLMKube ([#​2053](defilantech/LLMKube#2053)) ([16286c6](defilantech/LLMKube@16286c6)) - **metal:** fix install commands and update the quickstart for relay mode ([#​2087](defilantech/LLMKube#2087)) ([8bc7c6f](defilantech/LLMKube@8bc7c6f)) - use an extension-less link in the GPU fault guide ([#​2056](defilantech/LLMKube#2056)) ([780e710](defilantech/LLMKube@780e710)) ### [`v0.10.3`](https://github.com/defilantech/LLMKube/blob/HEAD/CHANGELOG.md#0103-2026-10-13) [Compare Source](defilantech/LLMKube@v0.10.2...v0.10.3) ##### Features - **api:** accept SGLang's Blackwell attention backends; flag flash_attn ([#​2033](defilantech/LLMKube#2033)) ([2385fd4](defilantech/LLMKube@2385fd4)) - **chart:** alert on GPU faults the device plugin ignores ([#​2031](defilantech/LLMKube#2031)) ([e4697ef](defilantech/LLMKube@e4697ef)) - **controller:** add opt-in vLLM engine-stall liveness probe ([#​2022](defilantech/LLMKube#2022)) ([429434a](defilantech/LLMKube@429434a)) - **controller:** apply the Model's HF_ENDPOINT mirror to runtime downloads ([#​2039](defilantech/LLMKube#2039)) ([cbececa](defilantech/LLMKube@cbececa)) - **controller:** stall-aware liveness for SGLang pods; share the detector ([#​2029](defilantech/LLMKube#2029)) ([212b014](defilantech/LLMKube@212b014)) - **router:** serve POST /v1/completions on the router-proxy ([#​2019](defilantech/LLMKube#2019)) ([1724a02](defilantech/LLMKube@1724a02)) ##### Bug Fixes - **controller:** bind SGLang dual-stack so it can become Ready on IPv4 clusters ([#​2028](defilantech/LLMKube#2028)) ([7d87c7e](defilantech/LLMKube@7d87c7e)) - **controller:** bound multiNode recreates and keep the failure evidence ([#​1996](defilantech/LLMKube#1996)) ([3331610](defilantech/LLMKube@3331610)) - **controller:** refuse to overwrite or delete a same-name HPA ([#​2010](defilantech/LLMKube#2010)) ([09affe5](defilantech/LLMKube@09affe5)) - **controller:** report a missing CA ConfigMap instead of wedging pods ([#​1995](defilantech/LLMKube#1995)) ([c624e02](defilantech/LLMKube@c624e02)) - **controller:** report AutoscalingReady=True when the HPA is managed ([#​2012](defilantech/LLMKube#2012)) ([b877ee5](defilantech/LLMKube@b877ee5)) - **controller:** split reconcileMultiNodeGroup under the gocyclo limit ([#​2000](defilantech/LLMKube#2000)) ([023a5c4](defilantech/LLMKube@023a5c4)) - **controller:** stop the prefetch status loop while the CA ConfigMap is missing ([#​2037](defilantech/LLMKube#2037)) ([b0b3cc6](defilantech/LLMKube@b0b3cc6)) - **foreman-agent:** make the repo package's git env hermetic and forward GIT_CONFIG\_\* ([#​2014](defilantech/LLMKube#2014)) ([62837d9](defilantech/LLMKube@62837d9)) - **router:** compile AgentGateway mode against Gateway API Inference Extension v1 ([#​1990](defilantech/LLMKube#1990)) ([ce817ba](defilantech/LLMKube@ce817ba)) - **router:** refuse to adopt same-name router-proxy objects ([#​2008](defilantech/LLMKube#2008)) ([e8f190a](defilantech/LLMKube@e8f190a)) - **router:** remove router-proxy objects for routers not in Proxy mode ([#​2006](defilantech/LLMKube#2006)) ([c04f824](defilantech/LLMKube@c04f824)) - **router:** stop truncating streams at the header timeout; quarantine stalled streams ([#​2026](defilantech/LLMKube#2026)) ([c4335c9](defilantech/LLMKube@c4335c9)) - **router:** time only upstream silence in the stream idle guard ([#​2035](defilantech/LLMKube#2035)) ([933426c](defilantech/LLMKube@933426c)) ##### Documentation - **air-gapped:** cover vLLM and SGLang safetensors checkpoints ([#​1993](defilantech/LLMKube#1993)) ([4d3fa70](defilantech/LLMKube@4d3fa70)) - replace deprecated Strix Halo GTT sizing with TTM parameters ([#​2003](defilantech/LLMKube#2003)) ([09d8d73](defilantech/LLMKube@09d8d73)) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNTEuMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE4MS45IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/2331
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.
What
Four follow-ups from the review of #2185 (#2158), all about staging the model cache on FUSE storage (BlobFuse and the like), where
flockdoes not exclude across nodes:ModelCacheLockUnsupportedrefusal and condition as multi-file models. FUSE detection now sits next tocacheDirLockin one prologue (cacheStagingPrologue) that both builders use.Pending, gets a newPrefetchWaiting=Truecondition (reasonPrefetchWaitingForStager) naming the Job and Model it waits for, and requeues every 15 s.ModelCacheLockUnsupportedremedy constant (prefetch,s3://, and local, which is new). The init script prints the remedy for its source. TheModelTransferHealthycondition takes the remedy from the termination message, so the log and the condition cannot disagree.OnChangeserving pod that keeps its cached copy now logsUpstream changed for <file>; a serving pod does not stage on a FUSE cache, so it kept the cached copy. Before, it logged an error followed by "Revalidation unreachable"..llmkube-sizerecord.llmkube_atomic_writetemp files are swept.Fixes #2250
Fixes #2254
Fixes #2251
Fixes #2255
Why
mkcachein the single-file builder tookcacheDirLockon any filesystem. On a BlobFuse RWX claim, two pods on different nodes could both hold the lock andcurl -C -into the same partial. That is the truncated-file race from [BUG] Concurrent multi-file staging into a shared ReadWriteMany cache can publish a truncated file that later pods accept #2158, and fix: validate multi-file cache staging on shared volumes #2185 had closed it only for multi-file models.flock. Two Models withprefetch: trueon the same source and the same claim each got their own Job, and the two Jobs wrote the same partials. Foreground deletion andpodReplacementPolicyonly order pods within one Job, not across Jobs.mktempandmvleft its temp file on the claim for good, because the sweeps only delete*.tmp.How
Shared prologue.
cacheStagingPrologue(remedy)detects FUSE (stat -f -c %t, magic65735546). It defines two shell functions:llmkube_fuse_reader: true for a serving pod on FUSE.llmkube_stage_allowed <file>: prints the refusal and returns 1 for such a pod.Off FUSE, it runs
mkdirand takes the lock. A stager on FUSE runs onlymkdir.The single-file branches use it this way:
llmkube_stage_allowed.rm -f "$MODEL_PATH.tmp", the OnChange debris sweep) are skipped byunlessFUSEReader.remoteRevalidateScripttakes acachedflag. With the flag set, a FUSE reader keeps a copy that passes the local checks, and otherwise refuses. Uncached callers render byte-identical output.Single-file stagers. The single-file downloader now carries
LLMKUBE_PREFETCH_STAGER=false, as the multi-file one already did. As a result:buildPrefetchJobflips that variable totruefor single-file Jobs too, so they are stagers.podReplacementPolicy: Failed.deletePrefetchJobdeletes them in the foreground.TestDeletePrefetchJobPropagationhas been updated to match. Its old case asserted background deletion for single-file prefetch Jobs. The background case now covers a Job built without the stager switch, which is what an older operator produced.Serialization (#2250).
startPrefetchTargetcallsactiveStagerright beforeCreate.activeStagerlists the namespace'sapp.kubernetes.io/component=model-prefetchJobs and Pods throughAPIReader(uncached).model-cachevolume) andCACHE_DIR(themodel-downloaderenv) from the pod spec. Jobs built by older operators are therefore recognised too.ModelReconciler.stagerStartMucovers both the check and theCreate. Without it, two of the four workers could both see "no stager" and both create one.listare already granted. A re-verification that has to wait keeps its entrySucceeded, so consumers keep serving.Remedy (#2251).
modelTransferSignaturegainedremedyFrom. ForModelCacheLockUnsupported, the remedy comes fromcacheLockRemedyIn(msg), which looks up whichever known remedy constant appears in the termination message. If the log tail cut the remedy off, it falls back to a pointer at the log. To carry the remedy,findModelTransferFailureandmatchModelTransferFailurenow return amodelTransferFailurestruct.#2255:
OnChangebranches checkllmkube_fuse_readerbefore they try to stage.fuseKeptCachedEchodistinguishes "unreachable" (no size from the origin) from "upstream changed".! llmkube_fuse_readeron the cache path, so the stager writes the record. The emptyDir path is unchanged.llmkube_atomic_writenow uses<dest>.llmkube-tmp.XXXXXXand removes its temp file when the write fails.*.llmkube-tmp.??????, plus the two unambiguous older names*.llmkube-size.??????and*.sha256-rejected.??????, once they are more than 10 minutes old (-mmin +10).<file>.sha256.XXXXXXstamp temp files are not swept, because a repository file could match that pattern. The docs say to delete them by hand.Consumers and rollout impact.
atomicWriteFn). Those pod templates roll once on upgrade. All 20 changed goldens ininternal/controller/testdata/were regenerated and read.#2057tripwire,TestCachePrepAlwaysTemplatesUnchanged, pins the default single-file Deployment and prefetch Job template hashes. Those pins move in the commits that change the template on purpose: Model cache: single-file cached models still stage on FUSE under a lock that does not hold #2254 (prologue and stager env) and the Model cache: smaller follow-ups from #2185 (OnChange FUSE log, stager backfill, temp file sweep) #2255 sweep. Each move has a reason comment, and docs/MODEL-CACHE.md now has an upgrade note.Pendingwith the message that names the blocker.finishJobDeletionand anAfterEachcollectPrefetchJobsto the two prefetch Describes. No assertion was weakened.Testing.
make gatepasses on the final commits (regen, drift, fmt, vet, lint-all, full test suite).buildModelStorageConfigandbuildPrefetchJob, run with their own env and a stubstat -f.stat -candflock, so they skip on macOS. I cross-compiled the test binary and ran every shell-executing test under BusyBox (curlimages/curl:8.18.0, the init image) and under Debian (golang:1.27.3). Both pass.Mutation checks. For each, I reverted the production change and confirmed the new test fails. Output below is quoted as captured. Some line numbers moved in later commits.
modelTransferSignatures.TestCacheLockRemedyLogMatchesCondition/{http,s3}failed:mkcache := mkdir -p "$CACHE_DIR" || exit 1; + cacheDirLockand dropped thellmkube_stage_allowedguard. All 18 FUSE cases ofTestSingleFileFUSEStagingand all 7 cases ofTestSingleFileFUSEWarmCachefailed:LLMKUBE_PREFETCH_STAGER=falseenv:OnChangerefresh.TestMultiFileFUSEWarmCache/OnChange/*/{offline,changed,changed-recorded}failed:cache_fs != FUSEbackfill condition.TestMultiFileFUSEStagerBackfillsSizeRecordfailed:TestCacheAtomicWriteDebrisSweepfailed:model_storage_fuse_test.go:707: model.gguf.llmkube-tmp.AbC123: removed=false, want truerm -fon a failed write.TestAtomicWriteRemovesItsTempOnFailure/mv-fails-truefailed:model_storage_fuse_test.go:747: temp files left behind: [.../record.llmkube-tmp.BnlcEK]$1.XXXXXX.TestAtomicWriteDebrisMatchesTheSweepfailed:model_storage_fuse_test.go:788: the sweep left the writer's temp files: [- model.safetensors.sha256.Ldfhhl]if false && blocker != ""). All three serialization specs failed. For example:[FAILED] a second stager on the same cache directory and claim must not be created Expected <bool>: false to be truehf://org/reposource withspec.files, sharing one claim):serializes stagers of a multi-file hf:// source shared on a claimfailed with[FAILED] a second multi-file stager on the same cache directory and claim must not be created Expected <bool>: false to be true(model_prefetch_serialize_test.go:177)stagerStartMu. Only the concurrency spec failed:DeletionTimestampfromprefetchJobActive.waits for a stager Job that is still being deletedfailed atmodel_prefetch_serialize_test.go:172.Not covered.
PrefetchWaitingmessage names it, and its own Model reports why.make test-e2e-rbacwas not run: the change adds no new resource, verb or API group.AI assistance: this change was AI-assisted. I reviewed the diffs and supervised the build.
Checklist
make testpasses locallymake lintpasses locallygit commit -s) per DCO