openclaw/test
Peter Steinberger 98742bc2c7
feat(cron): stream schedule sources with durable source identity (#112387)
* feat(cron): stream schedule sources (supervised command stdout)

Add gated argv stream schedules with bounded line batching and trigger.streamBatch composition.

Reuse the gateway ProcessSupervisor for source ownership, deterministic teardown, capped restart backoff, and schedule-key guarded batch execution. Expose additive protocol, CLI, tool, UI, docs, and generated snapshot surfaces without storage DDL.

Contract: stream schedules are event-driven, require cron.triggers.enabled, reject command payloads, and retain at most one bounded pending batch.

* fix(cron): reject retired stream source epochs at run admission

Thread an invalidatable per-owner source-generation token (ownerNonce.generation)
through cron.run admission alongside the schedule key. A batch handed to cron.run
under one source epoch can wait behind another run while its owner is stopped; a
disable→re-enable or A→B→A edit leaves the schedule key unchanged, so the key
check alone would admit the retired epoch's batch. The token is persisted in
job.state on every lifecycle write and compared at every admission site plus the
executeJobCore guard, so a stale epoch's batch is skipped.

Also fix direct stream-job mutations recording the wrong lifecycle status when
global cron is off but triggers are on: extract resolveStreamStopReason so the
direct path reports the remediable cron-disabled state like reconcile does.

* fix(cron): close stream admission windows from round-10 review

- Persist the retired source generation before draining stop teardown, so a
  batch queued behind another cron run cannot gain admission during the up-to-10s
  in-flight-batch wait (server-cron routed stop path).
- Add streamSourceGeneration to the closed gateway response schema (excluded from
  the writable patch schema) so a running stream job passes strict result
  validation without letting callers spoof source identity.
- Close the mutation-epoch ABA: track an eviction epoch so a snapshotted absent-0
  is trusted as unchanged only when no LRU eviction happened during the await.

* refactor(cron): stream sources own a durable logical identity

Split the conflated restart-generation/admission token into two concepts:
a persisted streamSourceIdentity owned by cron store mutations (rotates on
enable/disable, source replacement, once-trigger auto-disable, and explicit
retirement; stable across supervised child restarts) and a watcher-local
process generation used only to fence stale child callbacks. Admission now
requires schedule key + identity together at every window, closing the
A-to-B-to-A and restart-flush races from review rounds 8-11.

Also: match-mode regexes now see raw source text (the [truncated] marker is
applied after matching), stop-timeout failures set the live restartExhausted
mirror so shutdown preserves the terminal diagnostic, and the watcher is
split into owner/output/registry modules under the max-lines budget.

* fix(cron): harden stream teardown and intake from round-4 review

An exit queued ahead of a requested stop no longer counts toward restart
exhaustion (the synchronous stop fence owns it), overlapping cron.stop and
stopAndDrain share one memoized shutdown drain instead of double-stopping
every owner, raw output intake is bounded at 4x the batch cap so normal
64 KiB pipe reads stop losing complete lines to OS chunk boundaries, and
persisted-shape quarantine coverage for unsafe match expressions is pinned.

* fix(cron): keep watcher-internal owner disposal from retiring live identity

Disposing an obsolete owner while a start replaces it is not a durable
removal; a retiring stop there rotated the live job's identity and stranded
the replacement behind the CAS ownership guard. Also align the docs with the
implemented match semantics: complete lines match on full text past the
batch cap, only intake-cut prefixes are unmatchable.

* fix(cron): make oversized-line matching independent of pipe chunking

Partial lines are retained up to the raw-intake bound rather than the
delivery cap, so a complete over-cap line matches identically whether it
arrives in one callback or several; only a line the intake bound itself cut
remains an unprovable prefix. Reconcile also contains schedule-replacement
stop failures per job, matching the other stop branches.

* fix(cron): bound assembled lines, drop stale payload override, barrier stopAll

- enforce the 4x raw-intake per-line cap while assembling split callbacks,
  so an oversized line stays an unprovable prefix regardless of chunking
- stop passing the watcher-cached payload as a cron.run override; the run
  snapshots the persisted payload under its admission lock
- stopAll waits for every owner stop to settle before surfacing failures
- split cron-stream-output interleaving tests into their own file (max-lines)

* fix(cron): address first full-CI round (lint, knip, schema test, unused param)

* chore(cron): refresh codex prompt snapshots for stream schedule schema

* fix(cron): keep the first clean line after an intake drop ending at a newline

* fix(cron): fence stream reconcile list snapshots against direct mutation routes

A cron.list snapshot captured across the reconcile await could be applied
after a direct add/update route already started the owner, stopping it as
removed and retiring its live identity. A mutation revision bumped at every
direct route start invalidates the stale snapshot; reconcile re-lists
(bounded) instead of applying it.

* style(cron): format stream owner imports

* fix(cron): discard severed stream prefixes at EOF

* fix(cron): retry failed stream shutdown drains

* fix(cron): honor stream stop fence after output drain

* chore(cron): refresh landing checks
2026-07-21 15:01:30 -07:00
..
e2e/qa-lab fix(test): make broad shard execution deterministic (#111416) 2026-07-19 08:39:16 -07:00
fixtures feat(cron): stream schedule sources with durable source identity (#112387) 2026-07-21 15:01:30 -07:00
helpers refactor: own model discovery by runtime lifecycle (#111173) 2026-07-19 05:30:54 -07:00
mocks
plugins test: scale provider auth preload concurrency (#107849) 2026-07-14 17:01:51 -07:00
scripts fix(ios): keep snapshot results outside upload tree 2026-07-21 13:44:11 -05:00
tsconfig feat(setup): rename Crestodian to OpenClaw system agent 2026-07-14 11:03:02 -07:00
vitest refactor: remove expired plugin compatibility surfaces (#111451) 2026-07-19 11:04:48 -07:00
AGENTS.md
appcast.test.ts
architecture-smells.test.ts
CLAUDE.md
clawrouter-managed-gateway.e2e.test.ts test: tighten more async polling (#108454) 2026-07-15 13:37:53 -07:00
cli-json-stdout.e2e.test.ts fix(cli): keep config schema stdout parseable (#110496) 2026-07-18 08:02:04 +01:00
cli-state-sqlite.e2e.test.ts fix(sqlite): stop compaction before hard-linked WAL mutation (#112224) 2026-07-21 16:31:29 +08:00
embedded-transcript-cursor.e2e.test.ts fix: preserve transcript cursors across embedded turns (#111949) 2026-07-20 15:41:31 -07:00
extension-import-boundaries.test.ts
extension-package-tsc-boundary.test.ts
extension-test-boundary.test.ts refactor(plugin-sdk): remove private testing barrel ahead of window (#108020) 2026-07-14 22:13:37 -07:00
external-script-modules.d.ts fix: bound live updater gateway probes (#110509) 2026-07-18 08:16:05 +01:00
gateway-queued-session-rotation.e2e.test.ts refactor(config): purge numeric tuning knobs behind built-in defaults (#111382) 2026-07-19 07:35:45 -07:00
gateway.multi.e2e.test.ts
git-hooks-pre-commit.test.ts chore(autoreview): centralize secret scanning (#112036) 2026-07-20 22:59:20 -07:00
huggingface-local-app-openclaw.e2e.test.ts
image-generation.infer-cli.live.test.ts
image-generation.runtime.live.test.ts fix(ci): harden release validation gates (#108798) 2026-07-16 03:21:08 -07:00
linux-quickchat-stream.test.ts fix(linux): harden Quick Chat widget lifecycle (#112261) 2026-07-21 05:35:06 -07:00
mcp-show-redact.e2e.test.ts test: tighten more async polling (#108385) 2026-07-15 10:49:43 -07:00
non-isolated-runner.resolve-mocks.test.ts test: serialize Vitest mock resolution in isolate:false shared workers (#109874) 2026-07-17 11:54:54 +01:00
non-isolated-runner.test.ts test: clear plugin runtimes between shared files (#111556) 2026-07-19 15:28:46 -07:00
non-isolated-runner.ts test: clear plugin runtimes between shared files (#111556) 2026-07-19 15:28:46 -07:00
npm-publish-plan.test.ts
official-channel-catalog.test.ts refactor(channels): move channel-flavored setup flags into plugin manifests (#112239) 2026-07-21 02:50:19 -07:00
openclaw-launcher.e2e.test.ts fix(cli): preserve failure exit semantics (#112210) 2026-07-21 01:48:25 -07:00
openclaw-npm-postpublish-verify.test.ts fix(release): trust extended-stable npm provenance (#112301) 2026-07-21 22:32:42 +09:00
openclaw-npm-prepublish-verify.test.ts
openclaw-npm-release-check.test.ts
openclaw-prepack.test.ts fix(ci): preserve OCM workspace prepack (#107844) 2026-07-14 17:28:45 -07:00
package-manager-config.test.ts
package-scripts.test.ts fix(sessions): fsync archives through writable handles (#110191) 2026-07-17 15:16:50 -07:00
plugin-clawhub-release.test.ts ci: speed up release preparation 2026-07-17 13:43:12 +01:00
plugin-cron-registry-owner.e2e.test.ts fix(plugins): recurring plugin-scheduled jobs silently deleted after first post-boot agent turn (#107752) 2026-07-18 09:21:50 +01:00
plugin-extension-import-boundary.test.ts
plugin-npm-package-manifest.test.ts
plugin-npm-release.test.ts fix(release): plugin npm preflight no longer hangs on stalled registries (#110862) 2026-07-19 16:10:49 +08:00
plugin-npm-runtime-build.test.ts fix(plugins): restore external runtime imports (#112021) 2026-07-20 21:45:23 -06:00
qa-convex-credential-payload-validation.test.ts refactor(deadcode): enforce full-repository hard zero (#108717) 2026-07-16 00:16:20 -07:00
release-check.test.ts refactor: remove expired plugin compatibility surfaces (#111451) 2026-07-19 11:04:48 -07:00
setup-home-isolation.test.ts
setup-openclaw-runtime.ts refactor: own model discovery by runtime lifecycle (#111173) 2026-07-19 05:30:54 -07:00
setup.env.ts
setup.extensions.ts
setup.shared.ts fix(auth): session refresh preserves OAuth providers (#108680) 2026-07-16 00:39:28 -07:00
setup.ts
stable-release-closeout.test.ts
test-env.test.ts
test-env.ts refactor(config): purge numeric tuning knobs behind built-in defaults (#111382) 2026-07-19 07:35:45 -07:00
test-helper-extension-import-boundary.test.ts
tsconfig.json
ui.presenter-next-run.test.ts
vitest-boundary-config.test.ts
vitest-light-paths.test.ts
vitest-performance-config.test.ts
vitest-projects-config.test.ts fix(test): make broad shard execution deterministic (#111416) 2026-07-19 08:39:16 -07:00
vitest-scoped-config.test.ts fix(test): make broad shard execution deterministic (#111416) 2026-07-19 08:39:16 -07:00
vitest-ui-package-config.test.ts fix(ui): prevent cross-file mock leakage in Control UI tests (#111554) 2026-07-19 15:38:50 -07:00
vitest-unit-config.test.ts test: avoid duplicate coverage discovery (#109141) 2026-07-16 08:43:26 -07:00
vitest-unit-fast-config.test.ts fix: shard OpenAI transport stream tests (#109181) 2026-07-16 09:43:07 -07:00
vitest-unit-paths.test.ts
web-provider-boundary.test.ts