Phase 5 — Background-engine hardening (rides 0.19.0)#319
Merged
Conversation
…l with no live HoM spawn
…d index (migration 066)
…ince split maxsplit 2
…iled-cycle heartbeat assertion
|
Thanks for opening your first pull request on RoboCo! Quick checklist before review (most of these are enforced by CI, but worth a glance):
See CONTRIBUTING.md for the full workflow and the Code of Conduct for the community standards we follow. Welcome aboard — a maintainer will review shortly. |
…,L27,L14,L28,H19,M13,M14,H20,M16,M45,L25,M15,L24)
…001), hoist AuditLogTable import (PLC0415)
…the GrokCliProvider
…reflects grok agents
…ep so live cost reflects Anthropic cache spend
…ud 429 parks instead of crash-respawning
…ens roll into usage/cost summaries
…r's revisit counter survives a restart
…rates after 2026-08-31
…ilently falling back to a zero-usage env id
…ken-sweep test signatures)
…ck stays reachable
… tokens are bounded
…ry so a stolen cookie's exp is fixed
…t revokes the current jti
…w + jti revocation
[phase9] Auth hardening: bound agent tokens (iat/exp) + JWT jti revocation
[scan-fix] Phase 8: LLM providers / usage / billing
[Phase 7] schemas/conventions/MegaTask/API fixes (15 findings, scan-fix program)
Phase 6 — Panel frontend hardening (rides 0.19.0)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 5 — Background-engine hardening (rides 0.19.0)
Fifth phase of the 2026-07-06 full-codebase-scan fix program. Twenty verified background-engine findings + an e2e smoke module, all under the existing
## [0.19.0]CHANGELOG section. Stacks on Phase 4 (fix/scan-git-workflow, PR #318) — base isfix/scan-git-workflow; merge #318 first.Security
1bb82827) —release_executor.wait_for_cikeeps polling through the window on a non-success conclusion; onlyconclusion == "success"returns True and loop exhaustion returns False. A failed first attempt while a re-run was still in_progress no longer blocks a real release — a re-run that flips the same commit green still publishes.96214624,bc19cbb5) —sweep_orphan_release_locksruns atOrchestrator.startand deletes anyroboco:release_proposal:*Redis key whose UUID owner isn't in the in-flight approve registry. A restart mid-execute orphaned the mutex (TTL 3000s, no heartbeat) and a CEO retry gotalready_in_progressfor up to 50 min; after a restart the registry is empty so every surviving key is an orphan. Best-effort (Redis outage logs a warning, never crashes).bc19cbb5is a controller cleanup that dropped a# type: ignorethe per-task reviewer had waved through (usescast("asyncio.Task[None]", ...)underTYPE_CHECKING).Fixed
59525b20) —tiktok_client._refreshcommits the rotated tokens in an independent session before returning; a caller lock-loss rollback no longer discards them. TikTok already invalidated the old refresh_token, so the pre-fix discard was a permanent credential lockout.18ec8a5a) —x_engine.open_feature_spotlight_explorationre-arms past a stale exploration: past2*intervalwith no live HoM spawn, the stale one is cancelled and a fresh one originates (an exploration left PENDING with no live spawn no longer gates the engine silent).41494d4a) —x_post_service.reject()+video_post_service.reject()raise on an already-COMPLETED draft (no CANCELLED-on-a-live-post lie); Xedited_bodywrite deferred into the single-flight lock — the CEO's edit is applied to the re-read row after the in-lock COMPLETED check, so a concurrent approve that already posted can't have the edit land on the just-posted task.296d224e) —list_completed_video_tasksbounded.order_by(created_at.desc()).limit(video_render_scan_limit)(default 200) backed byix_tasks_source_status_created(migration 066), instead of re-reading every completed video task ever each cycle.b30ec223) — X_mark_seenruns after the meaningful + project checks (a low-engagement mention is no longer permanently marked seen; one that later goes viral is still draftable); X mentions persist thesince_idcursor in Redis so a burst >50 between ticks isn't silently dropped.cc2ef3ac) — release gate scoped to the read-clone HEAD (head_shapassed toget_latest_ci_conclusionso a stale older-commit CI run can't read "green" while HEAD's CI is in_progress; a missing HEAD falls to unknown → no proposal);_run_git30s timeout bubbles a clear error instead of hanging the thread;_commits_sincesplits withmaxsplit=2so a\x1fembedded in a commit subject/body no longer garbles the CHANGELOG line.557e432b) — dep_update dedupe by(git_url, dep_update_command): a monorepo with two distinct commands gets one open task per command, not one for the repo blocking the second ecosystem's drift.run_cyclefetches open tasks once and_eligiblechecks membership in-memory (TaskTable.projectislazy="joined", so the project row rides along in one SELECT — no N+1).f9fd1676,460e8798) — engine-loop liveness watchdog: each of the eight background engine loops (self_heal,ci_watch,dep_update,release_manager,x_feature_spotlight,video_render,x_mentions,roadmap_engine) records a monotonic heartbeat at start + after a successful cycle;_check_loop_liveness(called from_check_health) logs a warning whennow - last_success > 2 * interval. A silently-died cycle task stops recording → after2*intervalthe health loop logs "engine loop stalled".460e8798is a controller scope-widening commit: the brief listed six loops; the mentions-poll + roadmap-engine loops are also engine loops that could stall silently, so the watchdog now covers all eight.e2c8be48) —_run_video_render_cyclecommits after each_render_video_taskinstead of one trailing commit. A raise mid-cycle no longer rolls back prior renders (each is durable before the next is attempted), and the next cycle no longer re-renders + re-originates a second heldvideo_postdraft — the committedrender_status="rendered"is the idempotency key the next scan skips.ed3401a8) —_detect_stuck_tasksskips any task whose source is CEO-held (release_manager,x_post/x_reply,video_post, PR-review, self-heal pre-approve) before the age/issues check, reusing the existing_is_held_ceo_sourcehelper. A held draft sitting PENDING is no longer auto-blocked, wedging the held-artifact flow.d949b31a) —video_renderer_client._savewrites to{path}.mp4.tmpthenPath.replace(path)(atomic POSIXrename(2)). A re-render can no longer clobber the MP4 the panel is streaming mid-read — a reader sees either the old or the new file, never a half-written one.035e05ba) —self_heal._fingerprintdocumented as by-design stable per-signal (NOT per-run): the dedup's intent is one open fix task per regression signal, so a persistently-red CI signal doesn't open a second task every cycle. A documenting comment records the acceptance so a future reader/agent doesn't "fix" it into a per-run hash and reintroduce the dedupe collision. (Controller amended the commit subject — the implementer's original "current-state by design" was inverted; the code is a stable content hash, explicitly NOT current-state.)96214624) — the release-approve heartbeat shares oneredis.from_urlclient per approve (~40 per-tick pools collapse to one), opened inapprove()and closed in itsfinally.082fbcf3) —MultiProjectCITelemetrySource.fetchgathers per-project samples concurrently withasyncio.gatherso one slow GitHub 429 doesn't stall the whole sweep;Nones filtered.e2e smoke
tests/e2e_smoke/test_background_engines.py(6a078478) — 4 cross-layer scenarios: H24 (wait_for_cipolls through a non-success to a later success), H25 (orphan release-mutex sweep against real Redis db 15 — orphan deleted, in-flight preserved), M1 (TikTok rotated refresh-token survives a caller lock-loss rollback via the independent-session commit), M21 (_run_video_render_cyclecommits per-task — A's render + video_post draft durable despite B's raise). M11 skipped (a non-flaky liveness harness needs a controllable clock + running loop tick the in-process stack can't model; unit-covered bytests/unit/runtime/test_orchestrator_liveness.py). Each stub drives the real service method + real DB/Redis, mocking only the external legs the harness can't model (GitHub CI, TikTok egress, video-renderer sidecar). Deviations documented in the module docstring.Migration
296d224e) —ix_tasks_source_status_createdontasks(source, status, created_at), backing the M4 bounded render-loop scan.down_revision="065_rag_index_failures". No ENUM. Revision id 27 chars (fits the repo'salembic_versionVARCHAR(32)). Round-trip verified (upgrade head→downgrade -1→upgrade head).Verification
uv run ruff format+ruff check— clean on all Phase 5 changed files.uv run mypy roboco/— clean on changed files.test_release_executor.py(H24),test_release_proposal_orphan_sweep.py(H25+L34, 6 passed),test_tiktok_client.py(M1),test_x_engine.py(M2+M6+M7),test_x_post_service.py+test_video_post_service.py(M3+M5),test_video_engine.py(M4),test_release_readiness.py+test_release_manager_engine.py(M8+M9+L9),test_dep_update_engine.py(M10+L35),test_multi_ci_telemetry.py(L36, 4 passed),test_self_heal_engine.py(L11, 10 passed),test_orchestrator_liveness.py(M11, 9 passed — 8 loops + watchdog),test_video_render_loop.py(M21, 9 passed),test_orchestrator_stuck_tasks.py(M22, 2 passed),test_video_renderer_client.py(L6, 10 passed).make e2e-smoke— every Phase 5 scenario passes in isolation (4 passed). Full-suite session-scoped workspace contamination across e2e files is a pre-existing harness limitation, documented + out of scope.64d81fe2: corrected the e2e docstring's M11 unit-test filename (test_loop_liveness_watchdog.py→test_orchestrator_liveness.py) + strengthened the M11 failed-cycle test to spy on_record_loop_heartbeatand assert it fires exactly once (start heartbeat only, post-success skipped on a raised cycle). No production code changed in the fix wave.Model note
Implementers ran on sonnet; per-task reviews on sonnet; whole-branch review on opus. kimi-k2.7-code:cloud is not routable in this harness (flagged to CEO; accepted).
🤖 Generated with Claude Code