- _supplement_decision_logs: executing evals missing a decision log get a
platform-derived execute_session (deficit) or start_analysis (all sessions
done) entry. Audit backfill only — records observable state, does not change
agent execution. Called each scan tick after requeue+scan.
- t480 legacy cron workers (5) disabled: superseded by platform-triggered
headless agent (plan C); they kept firing every minute and failing on
Channel-required.
openclaw gateway fails to start when trusted-proxy and a shared token are
both configured (mutually exclusive). The env var was re-introduced on every
deploy because deploy-t480.sh rsyncs the repo compose file. Remove it so the
gateway runs in trusted-proxy mode; the agenteval proxy authenticates via
x-forwarded-user.
openclaw agent has no cron state; a bare 'agenteval-intelligent-worker'
message made the worker skill decide then 'wait for the next tick',
deadlocking (task assigned, session never created). The trigger message now
demands '立即完成当前任务,不要等待下一节拍' and, when all sessions are
done, delegates to agenteval-intelligent-analyst. Verified end-to-end on
t480: 1h-window eval went executing -> session (2 real turns) -> close ->
report -> completed, fully agent-driven, no external IM channel.
OpenClaw cron requires a channel (announce->last fail-closed); webchat is a
Control-UI feature, not an addressable channel, and platform-side static
execution would degrade the intelligent eval into a static evaluation.
Solution (plan C): the platform keeps the scan loop and, when the queue has
a pending task, invokes the headless agent:
docker exec openclaw-eval openclaw agent --agent main \
-m agenteval-intelligent-worker --json
--deliver defaults to false, so no cron delivery channel is involved. The
worker skill runs unchanged under the OpenClaw agent (LLM decisions +
evaluator/analyst skills). Verified headless invocation returns ok.
scan_and_enqueue_tasks had no scheduler: the OpenClaw Worker wakes every
minute but the platform never enqueued executing evals, so the queue was
always empty. lifespan now starts an asyncio background task that scans
executing intelligent evals every 60s (aligned with the Worker wake),
cancelled cleanly on shutdown. Verified by a new startup test (879 total).
- NaN root cause: report.scores is nested { overall, dimensions: {...} };
the old code treated every value as a number, so Number({object}) → NaN.
Now: dimScores from scores.dimensions, overall prefers scores.overall.
- Header summary cards restyled: icon + colored big number + responsive
(xs=12 md=6), colored score (>0.8 green / 0.6-0.8 amber / else red).
- usePolling gains a pauseWhenHidden option (default true): the timer
pauses while the document is hidden (background tab / minimised) and
resumes with an immediate reload on returning to visible. Callers keep
owning their initial fetch, so no duplicate first request.
- CronPoolMonitor now delegates its 5s poll to the shared usePolling hook
(initial load stays in its own useEffect); removes the bespoke
setInterval + manual visibility gap.
- CronPoolMonitor.test: visibility guard now passes (3/3), removing the
previous it.fails. Frontend suite: 18/18; tsc clean; backend 878.
Resolves scan §6.3.
- .scratch/v111-architecture-scan.md: mark §6.1, §6.2, §6.4
as RESOLVED (commits 38e3817, f85eca1, 6d32653); add §6.5
for T8 decision-log dedupe (commit 4bcab06).
- docs/release-notes-v1.1.0.md: add section ten listing the
four post-release fixes shipped to main after v1.1.1 was deployed,
so the release page documents what v1.1.1 production actually
contains (and what the v1.1.1 image does NOT contain).
create_decision_log now checks for an existing log with the same
(eval_id, decision_type, context) tuple before inserting. If found, it
returns the existing row's dict instead of appending a duplicate. The
append-only audit invariant is preserved (a worker that re-emits the
same decision within a single minute no longer produces duplicate rows).
Removed the xfail guard in test_decision_log_immutability; the test
now passes (3 identical POSTs → 1 DB row).
AlertManager gains an optional openclaw_client. check_alerts records
each newly created alert and AlertManager.maybe_autoscale (called
from the async router for each alert) invokes cron_pool.scale_up(1).
scale_up itself caps at MAX_POOL_SIZE so repeated invocations are safe.
Removed the xfail guard in test_alert_autoscale_link; rewrote the test
to use task_backlog (duration_minutes=0) so a single check_alerts call
fires an alert and triggers auto-scale.
_send_webhook:
- Dedupe: skip if alert.webhook_sent is already True (guards against
repeated check_alerts ticks re-sending the same alert).
- Retry: up to 3 attempts with exponential backoff (1s, 2s) before
giving up. webhook_sent=True is persisted only on success.
Two xfail guards in test_openclaw_client_and_webhook now pass (876/4 xfail).
Replace read-check-write in task_queue.assign_task with UPDATE...WHERE
status='pending' and decide on rowcount so two concurrent workers
cannot both claim the same task. Also harden complete_task with the
same CAS pattern (status='assigned') so a worker + stuck-handler
double-complete leaves the DB in one state.
The xfail guard in test_worker_task_resilience now passes (4/4).
bump commit 444e9d7 missed package-lock.json; CI version-consistency
check (sync_version.py --check) failed with OUT_OF_SYNC. This commit
brings the lockfile in line so CI/CD can pass.
P1 deepening (issue #7):
S1: is the single source of truth for time-slot parsing,
slot-due checks, session deficit, priority, attention reason, and
high-severity detection. and now delegate
their internal helpers to while keeping the same signatures
(tests continue to pass via the thin wrappers).
S4: encapsulates the stuck-cron
task settlement (fail current task + enqueue retry).
calls it instead of the previous runtime import of .
No observable behaviour change — 873 passed + 5 xfailed unchanged.
T2 frontend CronPoolMonitor: polls every 5s, unmount clears interval,
plus it.fails guard for missing visibilitychange listener (S6).
T3 router ORM contract: heartbeat updates fields + 404, decision-logs
POST persists + 404, GET lists inserted (guards S2 — must continue to
pass after router handlers move into a service in P3).
T8 decision-log immutability: append-only on context change passes;
dedupe of identical (decision_type, context) is xfail (real gap).
T7 alert→auto-scale: task_backlog alert recorded on first call (passes);
check_alerts never invokes auto_scale is xfail (real gap, §6.4).
All real gaps are logged in .scratch/v111-architecture-scan.md §6.
T4 auto-scale boundary: busy/total == 0.8 (exact threshold) must not fire
T4 auto-scale oscillation: repeated flips across 0.8 must respect MIN/MAX bounds
T9 stuck-detection critical edge: strict '<' semantics at 10min threshold
T9 detect_stuck_crons ignores non-busy: idle/stuck crons excluded even if stale
- Add Cron Pool Monitor entry to sidebar menu
- Install Docker CE CLI from Aliyun mirror for container exec
- Mount Docker socket for managing openclaw-eval container
- Fix OpenClaw CLI commands (cron add/rm/list instead of automations)
- Add gateway token auth for CLI access
Document the intelligent evaluation cron pool architecture:
- Cron pool management (5-20 workers)
- Task queue with priority scheduling
- Worker skill with autonomous decision logic
- Config snapshot management and comparison
- Decision process tracking and visualization
- Monitoring and alerting system
- Fault tolerance and recovery mechanisms
- Frontend UI for config history, decision process, and cron pool monitoring
Rename legacy v1.1 release notes to v1.1-legacy.md.
Add intelligent evaluation cron pool architecture:
- Cron pool management (5-20 workers)
- Task queue with priority-based scheduling
- Worker skill with autonomous decision logic
- Config snapshot management and comparison
- Decision process tracking and visualization
- Monitoring and alerting system
- Fault tolerance and recovery mechanisms
- Frontend UI for config history, decision process, and cron pool monitoring
All 853 tests passing.