Build Log · September 6, 2026

Unsticking Two Owner Loop Requests, a Parallel Admin Avenue, and Closing the Gate-Churn Loop

Recovered two MedinaCHF requests stuck at 'ready, waiting for review' with no visible cause, root-caused why the recovery path failed silently, built a way to do admin work without colliding with the Owner Loop, and finally built the gate-churn reduction the earlier Charge never actually delivered.

  • Alloy
  • Owner Loop
  • MedinaCHF
  • Reliability
  • OS
stuck MedinaCHF requests root-caused and recovered
2

stuck MedinaCHF requests root-caused and recovered

real MedinaCHF Owner Loop requests handled today
23

real MedinaCHF Owner Loop requests handled today

commits, all after the prior same-day retro closed
6

commits, all after the prior same-day retro closed

Timeline

  1. Start

    Zeb shows a screenshot: two requests stuck at 'Ready, waiting for review' with no visible action

    Rejected an initial 'probably stale cache' guess — demanded a database-grounded answer

  2. +30m

    Root-caused via direct DB read: both rows genuinely desynced between execution_state and dispatch_status

    One promotion_blocked/awaiting_promotion mismatch after a manual candidate merge, no existing script handled that exact shape

  3. +1h

    Built the first-ever script for this desync shape, recovered both requests

    fix-promotion-blocked-desync.mjs — narrow, exact-shape-guarded, refuses on any other mismatch

  4. +1h30m

    Found and fixed manual-deploy.yml missing a resolver DB credential — caused a false Gate B park on an already-resolved commit

    fetchOwnerRequestText couldn't read the owner's raw request without it

  5. +2h

    Confirmed both requests actually reached production, not just DB-finalized

    9e5a397c live; 2789eacd finalized

  6. +2h30m

    Zeb: 'we need a parallel avenue for admin work that doesn't collide with the Owner Loop'

    Weighed ripping out recovery machinery vs. two narrower options; Zeb chose both: a push-time liveness check AND a durable pause switch

  7. +3h

    Built checkActorSpawnLiveness (push-gate warning) and owner-loop-pause.mjs (a committed, explicit pause file)

    14 new regression tests across both mechanisms

  8. +3h30m

    Built a read-only admin_intents inspection GitHub Actions workflow

    Never reads .env.local directly — real secrets used server-side only, per security rule

  9. +4h

    Cost/usage investigation: real Actor Spawn cost data pulled from gh run logs, no session-level dashboard exists

    $43.35 across 15 genuine runs; confirmed no CLI-accessible usage API for interactive sessions

  10. +4h30m

    Zeb corrected the review framing: 'you are looking at the wrong thing' — redirected to the Charge's actual stated intent

    Reduce Smith's own procedural rediscovery of known gate-satisfaction steps, not re-verify the original bug stayed fixed

  11. Close

    Built and verified the actual gate-churn fix: a narrow marker-writer for the one pattern hand-typed 3 times this session

    Verified against checkMarker's real requirements, not just self-asserted

What shipped

  • forgekit-os/scripts/fix-promotion-blocked-desync.mjs — first-ever script for the execution_state/dispatch_status desync shape, exact-match guarded, refuses on any other mismatch

  • forgekit-os/scripts/inspect-admin-intent.mjs — read-only diagnostic (SELECT-only), added --since=YYYY-MM-DD mode

  • .github/workflows/inspect-admin-intent.yml — inspect / finalize / fix-desync jobs, dispatched with real repo secrets server-side

  • .github/workflows/manual-deploy.yml — wired resolver-db-url credential for all 5 apps (same case-block pattern as actor-spawn.yml), fixing false Gate B parks on redeploys of already-resolved commits

  • finalize job's checkout given fetch-depth: 0 — a shallow clone caused git rev-parse on a genuinely-reachable older candidate SHA to fail

  • .claude/hooks/lib/concurrency.mjs — checkActorSpawnLiveness(): warns (does not hard-block) a push when an Actor Spawn run is in_progress/queued/pending

  • .claude/hooks/gate-dispatch.mjs — pushTargetsMaster() (fixed a real bug: any git push origin <branch> was wrongly treated as targeting master) wired into checkPushGate, exempt inside worktrees

  • forgekit-os/scripts/owner-loop-pause.mjs — checkOwnerLoopPause/pauseOwnerLoop/resumeOwnerLoop against a committed (not gitignored) forgekit-os/owner-loop-paused.json, so toggling requires a real commit+push

  • forgekit-os/scripts/dispatch-owner-loop-requests.mjs — wired checkOwnerLoopPause() into main() before the circuit-breaker check

  • 14 new regression tests: .claude/hooks/tests/actor-spawn-liveness.test.mjs (9), forgekit-os/scripts/tests/owner-loop-pause.test.mjs (5)

  • forgekit-os/scripts/write-gate-marker-test-registration.mjs — narrow helper that verifies named test file(s) exist + pass node --check, then writes a correctly-shaped Dependency/Env-Config Gate marker in one call

“you are looking at the wrong thing. you should be looking at this... Reduce the time, tool calls, tokens, and Actor attention ForgeKit wastes repeatedly rediscovering how to satisfy its own established gates.”
— Zeb, correcting the review's framing mid-session