Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
75b1ac1
feat(onboarding): enable lean mode for local models (#110596)
steipete Jul 18, 2026
35754a6
fix(plugins): bound marketplace manifest file reads (#101774)
cxbAsDev Jul 18, 2026
609e5d2
fix(gateway): session workspace reveal hangs on foreground opener (#1…
zhangguiping-xydt Jul 18, 2026
f14947d
fix(codex): persist automatic compaction history (#110587)
steipete Jul 18, 2026
e721508
fix(ui): bound chat avatar fetches (#110010)
xydigit-zt Jul 18, 2026
39528ed
fix(security): restore fs import lost in bounded manifest-read merge
steipete Jul 18, 2026
b34d0a8
fix(gateway): bound usage.list days parameter to 100 years (#110552)
tzy-17 Jul 18, 2026
1af6d99
fix: surface cron errors for empty isolated agent replies (#100229)
zhangguiping-xydt Jul 18, 2026
2b04c35
fix(config): restore process.env after invalid config rejection (#103…
xialonglee Jul 18, 2026
fceae4d
fix(ui): bound managed outgoing image fetches (#108116)
chengzhichao-xydt Jul 18, 2026
95d632e
fix(security): bound skill-file audit read via safe reader (restore r…
steipete Jul 18, 2026
a941d3a
fix(shared): reject HTTP status codes outside the 100-599 range (#110…
tzy-17 Jul 18, 2026
7752e33
Revert "fix(security): restore fs import lost in bounded manifest-rea…
steipete Jul 18, 2026
fcdf06e
fix(config): ignore inherited keys when restoring env refs (#109463)
zenglingbiao Jul 18, 2026
a068d38
refactor(plugins)!: remove experimental workspaces plugin (#110416)
steipete Jul 18, 2026
e7fe47d
fix(browser): allow one retry after transient failures (#110607)
steipete Jul 18, 2026
7a7c158
perf(ci): parallelize gateway watch artifact check (#110609)
steipete Jul 18, 2026
8c95ec9
fix(ui): show sidebar connection state only on sustained disconnect (…
steipete Jul 18, 2026
b3650b7
fix(tui): exit reliably after quit (#110595)
steipete Jul 18, 2026
bf20509
fix: prevent TUI PTY tests from aborting after completion (#110610)
steipete Jul 18, 2026
fab3cdf
refactor(gateway): simplify lifecycle mutation contracts (#110583)
steipete Jul 18, 2026
21bd5a4
fix(chat): preserve explicit current-source sends in Control UI histo…
snowzlmbot Jul 18, 2026
04d7462
fix(plugin-sdk): attached send results report the configured channel …
mushuiyu886 Jul 18, 2026
42e6972
fix(opencode): Zen GPT-5.6 models are missing from discovery (#110405)
mushuiyu886 Jul 18, 2026
52d49a6
fix(plugin-sdk): refresh config schema API baseline (#110614)
steipete Jul 18, 2026
cb785ed
feat(ui): syntax-highlight the channel health snapshot on the channel…
steipete Jul 18, 2026
21c3438
feat(ui): merge voice and video talk into one button with in-call cam…
steipete Jul 18, 2026
2e21d53
fix(plugins): bound plugin manifest metadata file reads (#110036)
cxbAsDev Jul 18, 2026
16bd13d
fix(plugin-sdk): refresh channel send API baseline (#110620)
steipete Jul 18, 2026
e22c2df
fix(gateway): bound BOOT.md file read size (#101776)
cxbAsDev Jul 18, 2026
adff355
fix(plugin-sdk): failed raw channel sends report success (#109906)
mushuiyu886 Jul 18, 2026
cc92083
fix(android): recover Wear requests from stale phone routes (#110423)
cygnostik Jul 18, 2026
5360c75
fix(tui): stop Codex login lookup hanging the terminal (#109452)
mushuiyu886 Jul 18, 2026
bc6d9eb
fix: custom Anthropic models work without maxTokens (#110617)
steipete Jul 18, 2026
9d97e10
refactor: move non-session runtime journals to SQLite (#109427)
steipete Jul 18, 2026
4a96c9d
feat(ui): link Get the apps from the mobile pairing dialog (#110622)
steipete Jul 18, 2026
347ee45
fix(secrets): surface degradation in logs and doctor (#109792)
steipete Jul 18, 2026
f57a875
fix(ui): cap sidebar child sessions with show-more, drop Subagent pre…
steipete Jul 18, 2026
3131492
improve(ui): plugins hub hierarchy, settings section spacing, and gri…
steipete Jul 18, 2026
0ac69b9
fix(zalo): prevent webhook message loss after acknowledgment (#110630)
steipete Jul 18, 2026
3b2797f
improve(ui): settings cleanup batch — universal config.changed emitte…
steipete Jul 18, 2026
c989b8a
fix(ui): settings language picker was oversized and unthemed (#110621)
steipete Jul 18, 2026
01a9e1d
feat(memory): default cross-conversation recall for personal installs…
steipete Jul 18, 2026
0bbb862
fix(gateway): keep setup.detect off the event loop so health stays li…
steipete Jul 18, 2026
00257c3
feat(ui): theme cards preview their real color palettes (#110626)
steipete Jul 18, 2026
105aeba
fix: report agent deletion cleanup failures (#110560)
steipete Jul 18, 2026
b950354
fix: repair model refs after provider deletion (#110648)
steipete Jul 18, 2026
efa7e1a
fix(scripts): bound conflict-marker scan reads to prevent OOM on larg…
cxbAsDev Jul 18, 2026
60cb6d7
perf(ui): lazy-load the lobster pet out of the Control UI startup gra…
steipete Jul 18, 2026
05fb8e6
fix(cli): bound --message-file reads for agent command (#101442)
cxbAsDev Jul 18, 2026
e976e35
fix(security): bound mcporter registry read in audit (#101772)
cxbAsDev Jul 18, 2026
684ae08
fix(signal): preserve durable ingress retry ownership (#110629)
steipete Jul 18, 2026
f98bcb7
perf(ui): drop zod from the Control UI and lazy-load json5 with the c…
steipete Jul 18, 2026
39ddf71
feat(ui): session unarchive flows with undo toast (#110605)
steipete Jul 18, 2026
f6de912
refactor(update): split update-runner into focused modules under the …
steipete Jul 18, 2026
74880cb
feat(ui): manage MCP servers directly from Settings → MCP (#110654)
steipete Jul 18, 2026
bc8d0da
feat(linux): Quick Chat streamed replies and precise pairing states (…
steipete Jul 18, 2026
28069db
feat(macos): render system chat option cards (#110584)
steipete Jul 18, 2026
d3173f6
perf(ui): keep lazy-page CSS out of the Control UI entry stylesheet (…
steipete Jul 18, 2026
7994c44
fix(ios): shrink the chat "Jump to latest" pill to a compact icon but…
steipete Jul 18, 2026
af2662f
fix(reef): add timeout and bounded JSON reads to relay transport (#10…
cxbAsDev Jul 18, 2026
e01a880
refactor(state): split openclaw-state-db into focused modules under t…
steipete Jul 18, 2026
40793e6
fix: bound pasted input and provider response bodies (#110627)
steipete Jul 18, 2026
881b0a6
fix(doctor): bound AGENTS.md and root-memory file reads (#101448)
cxbAsDev Jul 18, 2026
1cddec3
feat(clients): session groups, batch actions, inspector, and worktree…
steipete Jul 18, 2026
ad3b8e0
fix(memory): bound qmd taskkill cleanup (#109265)
Alix-007 Jul 18, 2026
42133d0
feat(mac): show native notification permission in dashboard Notificat…
steipete Jul 18, 2026
b5d9573
fix: pause hidden session catalog polling
shakkernerd Jul 18, 2026
e4fd904
test: cover hidden catalog polling across reconnects (#110705)
shakkernerd Jul 18, 2026
9710a13
refactor(canvas): promote inline-widget hosting and show_widget to co…
steipete Jul 18, 2026
0acece4
feat(chat): rewind and fork a session from a message bubble (#110660)
steipete Jul 18, 2026
737bb0c
sync: merge upstream main through 0acece45912
devSejung Jul 18, 2026
05e8091
docs: record upstream sync head
devSejung Jul 18, 2026
2442f3f
fix(ci): authenticate private checkout fetches
devSejung Jul 18, 2026
fc1bf28
merge: refresh upstream sync against platform main
devSejung Jul 20, 2026
3e7a096
chore: refresh plugin sdk api baseline
devSejung Jul 20, 2026
a8145bd
ci(platformclaw): allow full sync validation
devSejung Jul 20, 2026
9a5fc44
fix(platformclaw): pass auth typecheck
devSejung Jul 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 0 additions & 5 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,6 @@
- "extensions/workboard/**"
- "docs/plugins/workboard.md"
- "docs/plugins/reference/workboard.md"
"plugin: workspaces":
- changed-files:
- any-glob-to-any-file:
- "extensions/workspaces/**"
- "docs/web/workspaces.md"
"plugin: migrate-hermes":
- changed-files:
- any-glob-to-any-file:
Expand Down
108 changes: 80 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,14 @@ jobs:
CHECKOUT_EVENT_REF: ${{ github.ref }}
CHECKOUT_FALLBACK_REF: ${{ github.sha }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [[ -z "$CHECKOUT_TOKEN" ]]; then
echo "checkout token is missing" >&2
exit 1
fi
auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')"
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
Expand All @@ -161,6 +167,7 @@ jobs:
for attempt in 1 2 3; do
timeout --signal=TERM --kill-after=10s 120s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
-c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${ref}:refs/remotes/origin/checkout" && return 0
fetch_status="$?"
Expand All @@ -184,6 +191,7 @@ jobs:
for attempt in 1 2 3; do
timeout --signal=TERM --kill-after=10s 120s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
-c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules --depth=2 \
--filter=blob:none origin "$sha" && return 0
if [ "$attempt" = "3" ]; then
Expand Down Expand Up @@ -807,8 +815,14 @@ jobs:
CHECKOUT_REF: ${{ inputs.target_ref || github.sha }}
CHECKOUT_FALLBACK_REF: ${{ github.sha }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [[ -z "$CHECKOUT_TOKEN" ]]; then
echo "checkout token is missing" >&2
exit 1
fi
auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')"
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
Expand All @@ -818,6 +832,7 @@ jobs:
for attempt in 1 2 3; do
timeout --signal=TERM --kill-after=10s 120s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
-c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules --depth=2 origin \
"+${ref}:refs/remotes/origin/checkout" && return 0
fetch_status="$?"
Expand Down Expand Up @@ -970,9 +985,16 @@ jobs:
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail

if [[ -z "$CHECKOUT_TOKEN" ]]; then
echo "checkout token is missing" >&2
exit 1
fi
auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')"

workdir="$GITHUB_WORKSPACE"
reset_checkout_dir() {
mkdir -p "$workdir"
Expand All @@ -990,6 +1012,7 @@ jobs:

timeout --signal=TERM --kill-after=10s 120s git -C "$workdir" \
-c protocol.version=2 \
-c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1

Expand Down Expand Up @@ -1137,6 +1160,7 @@ jobs:
id: built_artifact_checks
if: needs.preflight.outputs.run_checks == 'true' || needs.preflight.outputs.run_checks_node_core_dist == 'true' || needs.preflight.outputs.run_check_additional == 'true'
env:
PARALLEL_GATEWAY_WATCH: ${{ runner.environment != 'github-hosted' && 'true' || 'false' }}
RUN_CHANNELS: ${{ needs.preflight.outputs.run_checks }}
RUN_CORE_SUPPORT_BOUNDARY: ${{ needs.preflight.outputs.run_checks_node_core_dist }}
RUN_GATEWAY_WATCH: ${{ needs.preflight.outputs.run_check_additional }}
Expand Down Expand Up @@ -1164,6 +1188,29 @@ jobs:
pids+=("$!")
}

wait_checks() {
local index name log pid result
for index in "${!pids[@]}"; do
name="${names[$index]}"
log="${logs[$index]}"
pid="${pids[$index]}"

if wait "$pid"; then
result="success"
else
result="failure"
fi

echo "::group::${name} log"
cat "$log"
echo "::endgroup::"
results["$name"]="$result"
done
names=()
pids=()
logs=()
}

if [ "$RUN_CHANNELS" = "true" ]; then
start_check "channels" env \
NODE_OPTIONS=--max-old-space-size=8192 \
Expand All @@ -1178,36 +1225,19 @@ jobs:
node scripts/run-vitest.mjs run --config test/vitest/vitest.full-core-support-boundary.config.ts
fi

for index in "${!pids[@]}"; do
name="${names[$index]}"
log="${logs[$index]}"
pid="${pids[$index]}"

if wait "$pid"; then
result="success"
else
result="failure"
fi

echo "::group::${name} log"
cat "$log"
echo "::endgroup::"
results["$name"]="$result"
done
if [ "$RUN_GATEWAY_WATCH" = "true" ] && [ "$PARALLEL_GATEWAY_WATCH" = "true" ]; then
start_check "gateway-watch" \
node scripts/check-gateway-watch-regression.mjs --skip-build
fi

if [ "$RUN_GATEWAY_WATCH" = "true" ]; then
log="${RUNNER_TEMP}/gateway-watch.log"
echo "starting gateway-watch: node scripts/check-gateway-watch-regression.mjs --skip-build"
if node scripts/check-gateway-watch-regression.mjs --skip-build >"$log" 2>&1; then
result="success"
else
result="failure"
fi
wait_checks

echo "::group::gateway-watch log"
cat "$log"
echo "::endgroup::"
results["gateway-watch"]="$result"
# Preserve the low-core hosted path; concurrent Vitest can otherwise
# starve the Gateway readiness deadline used by this regression gate.
if [ "$RUN_GATEWAY_WATCH" = "true" ] && [ "$PARALLEL_GATEWAY_WATCH" != "true" ]; then
start_check "gateway-watch" \
node scripts/check-gateway-watch-regression.mjs --skip-build
wait_checks
fi

for name in channels core-support-boundary gateway-watch; do
Expand Down Expand Up @@ -2564,8 +2594,14 @@ jobs:
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [[ -z "$CHECKOUT_TOKEN" ]]; then
echo "checkout token is missing" >&2
exit 1
fi
auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')"
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
Expand All @@ -2574,6 +2610,7 @@ jobs:
for attempt in 1 2 3; do
timeout --signal=TERM --kill-after=10s 120s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
-c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/checkout" && return 0
fetch_status="$?"
Expand Down Expand Up @@ -2632,15 +2669,22 @@ jobs:
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [[ -z "$CHECKOUT_TOKEN" ]]; then
echo "checkout token is missing" >&2
exit 1
fi
auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')"
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
fetch_timeout_seconds=90
fetch_checkout_ref_once() {
git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
-c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/checkout" &
local fetch_pid="$!"
Expand Down Expand Up @@ -3110,9 +3154,16 @@ jobs:
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ needs.preflight.outputs.checkout_revision }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail

if [[ -z "$CHECKOUT_TOKEN" ]]; then
echo "checkout token is missing" >&2
exit 1
fi
auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')"

workdir="$GITHUB_WORKSPACE"
reset_checkout_dir() {
mkdir -p "$workdir"
Expand All @@ -3130,6 +3181,7 @@ jobs:

timeout --signal=TERM --kill-after=10s 120s git -C "$workdir" \
-c protocol.version=2 \
-c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/ci-target" || return 1

Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/platformclaw-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
name: PlatformClaw CI
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
runs-on: ubuntu-24.04
timeout-minutes: 45
timeout-minutes: 90
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
Expand All @@ -35,11 +35,14 @@ jobs:
with:
install-bun: "false"

- name: Run changed-surface checks
run: pnpm check:changed
- name: Typecheck PlatformClaw control plane
run: node scripts/run-tsgo.mjs -p packages/platformclaw-control-plane/tsconfig.json --noEmit

- name: Test PlatformClaw control plane
run: node scripts/run-vitest.mjs packages/platformclaw-control-plane/src

- name: Build PlatformClaw control plane
run: pnpm --dir packages/platformclaw-control-plane build

- name: Run changed-surface checks
run: pnpm check:changed
17 changes: 16 additions & 1 deletion .github/workflows/workflow-sanity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,14 @@ jobs:
env:
CHECKOUT_REPO: ${{ github.repository }}
CHECKOUT_SHA: ${{ github.sha }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [[ -z "$CHECKOUT_TOKEN" ]]; then
echo "checkout token is missing" >&2
exit 1
fi
auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')"
git init "$GITHUB_WORKSPACE"
git -C "$GITHUB_WORKSPACE" config gc.auto 0
git -C "$GITHUB_WORKSPACE" remote add origin "https://github.com/${CHECKOUT_REPO}.git"
Expand All @@ -40,6 +46,7 @@ jobs:
for attempt in 1 2 3; do
timeout --signal=TERM --kill-after=10s 30s git -C "$GITHUB_WORKSPACE" \
-c protocol.version=2 \
-c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --prune --no-recurse-submodules --depth=1 origin \
"+${CHECKOUT_SHA}:refs/remotes/origin/checkout" && return 0
fetch_status="$?"
Expand Down Expand Up @@ -96,8 +103,14 @@ jobs:
env:
BASE_REF: ${{ github.event.pull_request.base.ref }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
CHECKOUT_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [[ -z "$CHECKOUT_TOKEN" ]]; then
echo "checkout token is missing" >&2
exit 1
fi
auth_header="$(printf 'x-access-token:%s' "$CHECKOUT_TOKEN" | base64 | tr -d '\n')"
trusted_config="$RUNNER_TEMP/pre-commit-base.yaml"
trusted_zizmor_config="$RUNNER_TEMP/zizmor-base.yml"

Expand All @@ -106,7 +119,9 @@ jobs:
local target="$2"
local fetch_status
for attempt in 1 2 3; do
timeout --signal=TERM --kill-after=10s 30s git fetch --no-tags --depth=1 origin \
timeout --signal=TERM --kill-after=10s 30s git \
-c "http.extraheader=AUTHORIZATION: basic ${auth_header}" \
fetch --no-tags --depth=1 origin \
"+${ref}:${target}" && return 0
fetch_status="$?"
if [ "$fetch_status" != "124" ] && [ "$fetch_status" != "137" ]; then
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Docs: https://docs.openclaw.ai

### Fixes

- **Bounded input and provider responses:** cap pasted auth/config input and enforce wall-clock deadlines across generated-media downloads, polling JSON, and failed response details so oversized or slow-drip streams cannot exceed resource budgets (thanks @Pick-cat).
- **Cloud worker derived workspace caches:** exclude Python caches, dependency trees, and macOS metadata symmetrically from outbound sync and inbound reconciliation so local cache rewrites cannot fence later cloud results or worker reclaim.
- **Codex model status diagnostics:** report a configured Codex route as unavailable when its harness plugin is disabled, missing, or quarantined, while preserving the separate credential result and making `models status --check` fail instead of silently treating fallback execution as healthy. Thanks @shakkernerd.
- **Gateway control-plane rate limiting:** use per-method buckets with a 30-per-minute budget so interactive admin writes remain responsive while retaining runaway-loop protection.
Expand Down
Loading