* perf(pr): accept gate-proven in-progress CI runs for landing
verify-pr-hosted-gates required the whole CI run to reach completed,
but openclaw/ci-gate — the branch-protection check — needs every
selected lane and fails on any non-success, so a successful gate bound
to the run's check suite proves the merge-relevant outcome while
post-gate stragglers (timing summaries, artifact uploads) are still
running. prepare-run now accepts an in-progress run whose own gate
check succeeded, cutting one to several minutes per landing. Exact
attempt binding via check_suite id prevents a stale gate from a
previous attempt vouching for a rerun; gate proof only applies to the
exact head under verification, never recent-parent evidence.
* fix(pr): bind gate proof to the run attempt, not the check suite
Autoreview P1: check suites survive reruns, so a prior attempt's
successful gate could vouch for an in-progress rerun that has not
reached its own gate. The proof now goes through the attempt-scoped
jobs listing (filter=latest): the gate job must carry the run's own
run_attempt. Regression tests cover same-run/previous-attempt,
different-run, failed, and missing gate jobs.
* fix(pr): rely on filter=latest for gate attempt scoping
Autoreview P2: the REST list-jobs payload does not expose run_attempt,
so requiring it rejected every genuine rerun gate. loadCiGateJobs
already fetches per run with filter=latest, which scopes to the current
attempt, so a run_id match binds the gate correctly without the absent
field.
* fix(pr): declare ciGateJobs in the hosted-gates evidence typedef
* fix(pr): un-export the internal gate helper and loosen test id typing
hasSuccessfulCiGateJob is only reached through collectHostedGateEvidence,
so exporting it tripped the hard-zero deadcode gate; the new test also
typed workflow ids as number against the unknown-shaped return.
* fix(pr): bind early gate proof to the run attempt
Autoreview P1: workflow attempts share a run id and filter=latest keeps
a not-yet-rerun job's prior-attempt execution, so a partial rerun could
surface an old successful ci-gate. The REST job payload does expose
run_attempt (verified live), so fetch the attempt-specific jobs endpoint
and require the gate job's run_attempt to equal the run's.
* fix(pr): revalidate the run attempt after loading gate jobs
Autoreview P2: a rerun starting between the workflow-run snapshot and the
attempt-specific jobs fetch could return a stale prior-attempt gate. Re-read
the run after fetching its jobs and drop the evidence if the run completed or
its attempt advanced, so early proof only applies while the same attempt is
still pending.
* fix(install): reject runtimes with broken npm
* test(installer): use real Node for npm selection
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(ci): address reviewer findings across the perf-lever batch
Seven follow-ups from Codex review feedback on the landed CI perf PRs:
docker packaging switches to the full build profile (the ciArtifacts
step env clobbered its canonical-dts requirement); the boundary sticky
restore gates on generative source tree OIDs in both lanes, making
restored artifacts valid by construction (kills the clock-skew mtime
false-skip and ghost declarations from deleted sources); the node-test
worker budget derives from nproc instead of the runner label (labels
over-promise under load) and keeps the 2-worker cap when plans can
overlap; the deadcode task falls back to serial Knip below 8 cores;
the lint-lane i18n verify also runs for any ui-touching diff (keys are
extracted from all ui sources, not just ui/src/i18n); the oxlint
concurrency diagnostic moves to stderr; and workspace packages join
the prompt-snapshot always-run surface.
* fix(ci): fingerprint every generative source the boundary artifacts consume
Autoreview flagged inputs outside the tree-OID gate; toolchain, config,
and script inputs were already covered by the sticky key hash, but the
old actions/cache key also fingerprinted src/plugins/types.ts and
src/video-generation sources the OID list missed. Add those plus
src/channels (the plugin-sdk declaration graph reaches its public
types) to the fingerprint in all three sites.
* fix(ci): fold runner toolchain identity into the boundary sticky fingerprint
Autoreview: the sticky key hashes config/scripts/package.json/lockfile,
but a node/pnpm toolchain bump (pinned in the workflow, not the key)
could leave the key unchanged and bless artifacts built with the prior
toolchain. Record node/pnpm versions alongside the source tree OIDs in
all three fingerprint sites so a toolchain-only change forces a cold
build.
The child published its pid with a non-atomic writeFileSync while the test
polled file existence only, so a loaded runner could read an empty pid file
(NaN -> isProcessAlive false). Publish the pid via rename and widen the
spawn-chain poll deadlines; assertion strength is unchanged.
* feat(android): add Wear proxy protocol
Introduce a bounded, versioned phone/watch RPC contract and wire its test, lint, and build gates before either runtime endpoint lands.
Co-authored-by: Sebastian Schubotz <git@sibbl.de>
* test(android): lock Wear wire names
Cover every supported RPC method and event discriminator so phone and watch cannot silently drift.
Co-authored-by: Sebastian Schubotz <git@sibbl.net>
* fix(android): bound Wear JSON depth
Reject excessively nested Data Layer envelopes before kotlinx.serialization can recurse through them.
* fix(android): enforce Wear depth on encode
Keep outbound messages inside the same JSON nesting contract enforced by the decoder.
* fix(android): preflight Wear payload depth
Traverse arbitrary JSON payloads iteratively before serialization so deeply nested local trees fail safely.
* feat(android): add Wear phone proxy
Co-authored-by: Sebastian Schubotz <git@sibbl.net>
* fix(ci): repair Wear and docs sync checks
---------
Co-authored-by: Sebastian Schubotz <git@sibbl.de>
Co-authored-by: Sebastian Schubotz <git@sibbl.net>
* perf(ci): run the deadcode Knip scans concurrently
check-dependencies spent ~194s running seven Knip child processes
strictly serially (three package scripts, each iterating its scans).
The scans are independent processes over separate configs: both
deadcode scripts now Promise.all their scans, the CI task launches the
three package scripts concurrently with buffered logs, and the lane
moves to the 16 vCPU class for core/memory headroom. The
missing-exports-script contract violation now fails fast before
launching scans. Local: unused-files 218% CPU, 37s wall.
* test(ci): align prerelease plan with the 16 vCPU dependencies lane
The child wrote its pid with fs.writeFileSync, which makes the file visible at
open() (0 bytes) before the content lands. Under CI load the existsSync-gated
reader in waitForFile could observe the empty file, so readFileSync returned ''
and Number.parseInt yielded NaN, making isProcessAlive(NaN) false and failing the
pre-kill liveness assertion (checks-node-compact-small-6 flake). Write the pid to
a temp file and rename it into place so the path only appears with full content.
* perf(ci): unblock parallel oxlint shards and gate the lint-lane i18n verify
check-lint is the slowest static lane (median 252s): the control-UI
i18n verify runs 86s unconditionally and the three oxlint shards run
serially (89s) because the parallel gate demands 48GB of memory — a
local-Mac threshold that Blacksmith's 32GB 16 vCPU class can never
meet. CI now parallelizes shards at 8+ cores / 24GB+, and the lint case
reuses the existing run_control_ui_i18n manifest gate so diffs that
cannot affect generated catalogs skip the verify while oxlint always
runs.
* chore(ci): print oxlint shard concurrency decision
The lint-lane validation run still executed shards serially on a 16
vCPU runner; one log line exposes the resolved concurrency and the
host resources the decision saw.
Shards that pin a short no-output timeout (agents-core stripes) die fast
on the known warm-cache stall, but a cold Vitest module cache makes the
same imports legitimately silent for minutes - the in-job retry then
re-dies at the short limit without running a single test (observed 4x
on agents-core-runner-cli-2 today). Raise the retry attempt's window to
the 300s watchdog floor while keeping the fast first kill.