Privatizes unused script implementation declarations and removes one dead release-plan marker without changing command, build, release, or CI behavior.
* fix(ios): handle App Store versions without a selected build
* feat: schedule weekly mobile store releases with Discord results
* fix: admit scheduled mobile store uploads
* fix: suppress embeds in mobile release notifications
* fix: clarify mobile release notification headlines
fix(ci): keep the stale PR scan going when a PR is at the 100-label limit
The Stale workflow posted its inactivity warning and then added the `stale` label unconditionally. On a PR that already had 100 labels, GitHub rejected the label with 422 ("Issues cannot have more than 100 labels") and the whole scan aborted, so later PRs were never evaluated and the job went red. That 422 is now recorded as a per-PR outcome: the warning comment receipt is kept (no duplicate warning on the next run), no other labels are removed, and the scan continues. Every other error still fails the job.
Proof: the capacity regression failed before the fix; all 114 lifecycle tests pass after. A real dispatched scan evaluated 188 PRs, recorded two capacity outcomes, kept the existing warnings and advanced its cursor.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(ci): close stale PRs despite automated review activity
* fix(ci): resume stale closures across Barnacle app failover
* fix(ci): align stale lifecycle lint and workflow guards
* fix(ci): preserve stale warning and edit provenance
* fix(ci): retain activity and checkpoints across stale races
* test(ci): align stale checkpoint recovery guard
* fix(ci): preserve stale scan progress on all failures
* fix(ci): recognize REST draft activity events
GitHub can persistently fail a 100-job page of a CI attempt with a slow
502 while smaller pages of the same range succeed. The shared client's
in-request 5xx retries then exhaust the 30-second read deadline, and
recovery restarts against the same URL until the budget runs out, leaving
the combined openclaw/ci-gate status pending.
List attempt jobs at 100, then 50, then 25 per page. Above the floor, a
5xx skips in-request retries and the same offset range is requested
again at half size. The 25-job floor keeps the normal read retries,
deadline, and recovery restarts; read timeouts still restart the full
evaluation with fresh authority, and enumeration must still reach the
reported total.
## What Problem This Solves
Security Review starts an Actions run for every PR comment create, edit and delete in this repository, then skips almost all of them. On 2026-10-11 it started 30,115 runs in 24 hours; in a 100-run sample, 75 were `clawsweeper[bot]` comment events that ended `skipped`. GitHub creates a run per subscribing workflow before job conditions apply, so the job-level filter cannot prevent this.
## User Impact
No change to the approval contract: `/allow-security-sensitive-change` and `/allow-dependencies-change` comments, and the edits or deletions that revoke them, still re-evaluate the guards, and authorization is still read from live comments. Approval-command activity reaches Security Review a few seconds later because it now hops through the shared listener. Projected saving: roughly 29k Actions runs per day.
## Why This Change Was Made
- `ClawSweeper Dispatch` already receives every comment event (it is the shared listener since #169355). It now also subscribes to comment `deleted` and runs a `security-review-command` job only when the comment or its previous body mentions an approval command. That job checks out the existing `parseApprovalCommands` helper (same parser the resolver used), confirms a real command, and runs `gh workflow run security-review.yml -f pull_request=<n>` with `GITHUB_TOKEN`. The existing `dispatch` job ignores `deleted` comments, so ClawSweeper intake is unchanged.
- `Security Review` drops `issue_comment` and gains a `workflow_dispatch` input naming the PR. The resolver accepts that dispatch only when the payload sender is GitHub Actions (`id` 41898282, `github-actions[bot]`, `Bot`); manual dispatches by people keep failing with the existing "requires an automatic pull request or CI event" error before any API call. The input only selects the PR; the review job reads approvals from live comments as before.
- `merge-prior-ci-security.mjs` accepts a Security Review publisher with event `workflow_dispatch` only when the run actor is that same GitHub Actions identity. `issue_comment` publishers remain accepted because statuses published before this change are still valid evidence.
- zizmor flagged an `if:` check on `github.actor` as spoofable, so the identity check lives in the resolver on the immutable sender ID instead.
For SecOps: the forwarding job in `clawsweeper-dispatch.yml` is now part of the revocation path. Please decide whether that file (or the job) should join the SecOps CODEOWNERS closure; this PR does not change CODEOWNERS.
## Evidence
- Focused tests (473 passed across `security-review-workflow`, `security-review-event`, `security-review-script`, `pr-merge-prior-ci*`, `ancillary-workflow-concurrency`, `clawsweeper-dispatch`):
- the listener step runs as real bash with a stub `gh` against the full approval-command table that previously lived in the resolver tests: creates, previous-body revocations and deletions dispatch exactly `workflow run security-review.yml --repo openclaw/openclaw --ref main -f pull_request=42`; prose, quoted, uppercase, suffixed and mixed comments do not;
- the listener must keep `created`, `edited`, `deleted` comment subscriptions;
- the resolver selects the PR for a GitHub Actions dispatch and rejects dispatches from a user, a spoofed login, a wrong ID, and another bot before any API request;
- the prior-CI verifier accepts an automation-dispatched publisher and rejects a human-dispatched one.
- `node --import tsx scripts/check-workflows.mts` (actionlint, zizmor): passed.
- GitHub sets `actor` and `triggering_actor` to `github-actions[bot]` (`Bot`) for `GITHUB_TOKEN` `workflow_dispatch` runs; observed on openclaw/clawsweeper run 38180548598.
- Live negative proof: a manual `workflow_dispatch` of this branch's `security-review.yml` by a maintainer (https://github.com/openclaw/openclaw/actions/runs/38183944875) failed in the resolver with "Security review requires an automatic pull request or CI event." and published no status.
- Limit: `issue_comment` workflows run from `main`, so the end-to-end comment → dispatch → review path can only be observed after merge. I will post a test approval command and its deletion on a disposable PR after merge, confirm both re-evaluations and the `openclaw/ci-gate` status, and compare hourly Security Review run counts.
* fix(ci): make informational security notices easier to spot
* fix(ci): keep informational notices at body text size
* fix(ci): lead with the security approval outcome
## What Problem This Solves
CI and release tooling still carries retired selection paths, duplicate evidence projections, and single-use command factories that make its current behavior harder to follow.
## User Impact
No user-visible change. CI keeps the same jobs and gates; release receipts, manifest digests, CLI output, packaging contracts, and generated Gateway protocol bytes stay compatible. No SDK API, config, wire, or persisted-data changes.
## Why This Change Was Made
This batch removes **1,235 net production/tooling lines** (890 added, 2,125 deleted; tests excluded).
- Remove the unused extension fallback and core-impact classifier after their production caller was retired in `6a501796576`. The current planner consumes explicit targets; meaningful coverage now exercises that path. Remove unused current-planner options while retaining arguments needed by September frozen targets.
- Use the existing grouping helper and direct descriptors for CI shards; let the Docker lane constructor own its default command and remove one-use factories. Selection, lane ordering, prerequisites, and commands remain identical.
- Reuse release-policy child topology, evidence projections, and canonical JSON sorting; remove always-empty advisory machinery. Share the existing postpublication diagnostic schema while retaining the observer's `startup_failure` extension and historical receipt validation.
- Cross-OS packaging now uses the canonical package helper directly instead of maintaining a second pack/inventory implementation. That helper predates July 2026 and exists in all 36 available July-or-later release tags. Remove npm-runner forwarding and test-only APIs.
- Simplify docs translation fence/link processing and remove unused route, cursor, and split-depth state. Replace hand-written ZIP CRC with Node's implementation; remove an unreachable Swift fallback, retired cancellation adapter, and redundant timing/tarball branches.
- Keep the actual core consumer of the shared package metadata helper in Knip's graph, rather than suppressing a dead-export warning.
## Evidence
Remote proof uses [Blacksmith Testbox run 37090710184](https://github.com/openclaw/openclaw/actions/runs/37090710184), lease `tbx_01m3zt7sykcrdm1fq4m8zf4bz4`, with dependencies installed. Final source tree `3b3f07ba57325ab7da7335fd125dec0fd43216ac` matches commit `8c147759f7a8047189daf2ac0bacd4ae4f5b88d9`. After full-sync timeouts, targeted transfer plus whole-tree verification completed the proof.
- Focused TypeScript selection: **1,988 tests passed across 30 files**, about 398 seconds including the wrapper. Changed-test single-worker proof: **629 passed**; tooling shard 308.96 seconds. The root retention test passed all four cases. An additional eight-file selection passed **255 tests**, 30.16 seconds including the wrapper.
- `cd scripts/docs-i18n && go test ./...`: passed, package time 0.179 seconds.
- Base/candidate comparisons: **393 release output/error/digest comparisons**, **1,234 Docker comparisons across 727 plans**, **24 extension selection/packing comparisons**, and four Node shard-inventory profiles passed. Generated Swift protocol output is byte-identical.
- `pnpm test <changed files> --maxWorkers=1` retains the expensive real-repository ownership assertions: source-owner file 87.778 seconds; cross-OS release checks 0.971 seconds; workflow control 0.486 seconds; extension preparation 0.272 seconds. No new CI job or added test budget.
- Independent autoreview found no actionable P0/P1 regression. Final `check-changed` passed, including types, lint, package boundaries, ratchets, and all three unused-export scans. Both import-cycle checks reported **0**. Final single-worker replay of npm locks, cross-OS packaging, and release summaries: **306 tests passed**, 30.82 seconds including the wrapper.
Fixes found along the way: no separate product bug was established. Gate findings were corrected in the owning changes; tests were not weakened to conceal failures.
Lost CI-completion deliveries can leave the required ci-gate status pending after CI finishes. Add scheduled reconciliation through the existing trusted Security Review resolver and enforcement job.
Preserve overlapping completion windows, reject incomplete listings before publication, keep provisional statuses eligible, and trust only Actions-owned gate statuses. Bound each pass to the oldest 100 heads and retain the successful window anchor while a backlog remains.
Reruns whose original creation time predates the three-hour listing margin retain the documented existing recovery path through a push or Security Review rerun.
Validation: exact-head CI passed, focused entry-point and workflow regressions passed, and live read-only GitHub transport proof completed. Production scheduled recovery remains post-merge proof.
Consolidate repeated tooling flows while preserving command contracts. Fix swallowed HTML translation errors and browser-realm error handling in the Google Live smoke. Owner tests and CLI parity passed on Testbox; final broad gate replay follows a fixture lint correction.
Cancellation did not prove an infrastructure error or absence of executed
and failed tests, yet the sweeper automatically replayed whole workflows.
The three-day census found nine such reruns, including five CI workflows.
Remove canceled-run revival. Keep bounded recovery for missing or
startup-failed CI before tests execute, with infrastructure warnings and
the existing live head/PR checks.
The actual sweeper boundary changed from one canceled-run replay to zero
without a PR mutation. Both shared-fixture importers passed 20 standalone
runs and three replays under their CI configs on Testbox.