Build Log · October 2, 2026

Foreman owns recovery; Zeb handles exceptions

Foreman now budgets recovery by actions it actually ran, routes every stuck reason by Zeb's named split, writes every handoff onto the request itself, and deploys verified bytes from one isolated checkout - proven live on canvas-2 and on a real canvas-1 owner deploy.

  • Foreman
  • Owner Loop
  • Empty Canvas
  • Deploy provenance
commits shipped
11

commits shipped

live acceptance runs used (passed)
1 of 2

live acceptance runs used (passed)

production deploys with host confirmed
4

production deploys with host confirmed

audit findings fixed before push
1 blocker + 7

audit findings fixed before push

What shipped

  • forgekit-os/scripts/lib/promotion-blocked-reasons.mjs - the one classification of stuck-promotion reasons by Zeb's split (auto / agent / zeb / unknown), data-driven, byte-identical in all four canvas apps and drift-tested

  • forgekit-os/scripts/foreman/recovery-ledger.mjs + foreman_recovery_attempts (Foreman schema v2, provisioned and verified live on canvas-1..4) - budgets count EXECUTED actions, per (request, execution, recipe) plus a per-request rebuild cap; due-first fair follow-up

  • forgekit-os/scripts/foreman/recovery-facts.mjs - three-valued facts (candidate on master via GitHub compare API; retry columns; active pause)

  • forgekit-os/scripts/foreman/recovery-adapters.mjs - fixed recipes with preconditions actually evaluated; thenRun deleted; only open (needs_review) requests are ever recovered

  • forgekit-os/scripts/foreman/recovery.mjs - compare-and-set on every request write, handOffToPerson written on the request at decision time, freshDispatchRequest rebuild, exhaustion preserving the original reason

  • forgekit-os/scripts/foreman/authority.mjs - ACTION_AUTHORIZED_APPS plus RECOVERY_LIVE_APPS staged-rollout gate (canvas-2 first, then all four)

  • forgekit-os/scripts/dispatch-owner-loop-requests.mjs - fetch_failed joins the bounded promotion retry

  • forgekit-os/scripts/unblock-after-manual-promotion.mjs, fix-promotion-blocked-desync.mjs - writes now compare-and-set on the inspected state

  • forgekit-os/scripts/record-promotion-outcome.mjs - no immediate email for reasons Foreman owns where recovery is live

  • forgekit-os/scripts/foreman/rules/promotion-blocked-unrecovered.mjs - recheckResource id bug fixed; routing and severity from the shared classification

  • forgekit-os/scripts/foreman/notify.mjs - escalations carry the decision needed; human_notified_at stamped only on confirmed delivery

  • experiments/canvas-1..4/lib/promotion-blocked-class.ts + request-display.ts (+ canvas-1 RequestPanel.tsx, canvas-1/2 owner-loop-stage.ts) - owners see only on it / alerted / needs someone; none asks the owner to act

  • forgekit-os/scripts/lib/isolated-checkout.mjs - one detached worktree of the approved revision for verification AND packaging, link-aware dirtiness

  • forgekit-os/scripts/promote-app.mjs - Actor deploy path verifies and packages from the isolated checkout; upload digest; production host must positively serve the new deployment

  • forgekit-os/scripts/deploy-with-bundled-deps.mjs - manual deploy path rebuilt the same way; stamps uploadDigest and sourceTreeId

  • forgekit-os/scripts/provision-foreman-tables.mjs - ledger DDL and grants; skips index creation on tables it does not own

  • forgekit-os/scripts/foreman/acceptance/{probe-stuck-requests,find-acceptance-subject}.mjs + acceptance-probe expect-interrupted-after-publication / authenticity check; acceptance workflow gains after_publication mode and the GH token it was missing

  • Tests: promotion-blocked-reasons (11), recovery-bounded-retry (26), recovery-adapters (29), recovery-acceptance (10), promote-isolated-checkout (10), deploy-upload-binding (6), rules-fixtures (25); test:os exit 0 on frozen 692ed0b6

“Notification timing must not determine who supposedly owns the work.”
— Zeb's pasted review, before rollout