Skip to content

fix(automation): bind a flow published while the server runs, without a restart - #2576

Merged
os-zhuang merged 1 commit into
mainfrom
fix/automation-publish-rebind
Jul 4, 2026
Merged

fix(automation): bind a flow published while the server runs, without a restart#2576
os-zhuang merged 1 commit into
mainfrom
fix/automation-publish-rebind

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #2560 (cold-boot flow binding). A flow published while the server is running — the Studio online-authoring journey (author a record-triggered automation, publish it, immediately update a matching record) — did not fire. Its trigger only bound on the next process restart.

Two gaps, both fixed:

  1. The publish path fired no rebind signal.POST /packages/:id/publish-draftsprotocol.publishPackageDrafts promotes drafts to active but emitted no event the automation service listens to. The runtime dispatcher now announces metadata:reloaded after a successful publish — the same signal a dev artifact reload fires (MetadataPlugin._reloadAndAnnounce) — so boot-cached consumers re-sync without a restart. Best-effort: a subscriber failure never fails the publish (drafts are already live); it rides the response as rebindError. Fires only when something was published/unhidden.

  2. The runtime re-sync read the wrong source. The automation service's metadata:reloaded re-sync pulled metadata.list('flow'), which returns 0 in a real running server (it does not surface inline app flows), so even when the hook fired it bound nothing. It now reads protocol.getMetaItems({ type: 'flow' }) — the same flattened flow view fix(automation): bind flow triggers on cold boot, not just after HMR reload #2560's cold-boot bind and GET /meta/flow use — via a shared readFlowDefsFromProtocol helper, while keeping the teardown of flows removed from the artifact. A failed or unavailable protocol read returns null and is a no-op — it never tears down live flows. The kernel:ready cold-boot bind stays additive (no teardown), reusing the same helper.

Only one metadata:reloaded subscriber exists (the automation service), so firing it on publish has no collateral effect. Production is largely unaffected — a deploy reboots the process, so #2560's cold-boot bind covers it; this closes the gap for dev and single-instance Studio authoring.

Changes

  • packages/services/service-automation/src/plugin.ts — extract readFlowDefsFromProtocol; metadata:reloaded re-sync (resyncFlowsFromMetadataresyncFlowsFromProtocol) reads the protocol and keeps teardown; syncFlowsFromProtocol (kernel:ready) reuses the helper, stays additive.
  • packages/runtime/src/http-dispatcher.ts — announce metadata:reloaded after a successful publish-drafts.

Tests

  • Newflow-publish-rebind.test.ts (4 cases): binds a flow that appears in the protocol after boot; tears down a flow the protocol no longer serves; reads the protocol, not metadata.list (the exact bug); does not tear down live flows on a failed protocol read. The first/third fail on the pre-fix code.
  • Newhttp-dispatcher.test.ts cases: publish-drafts announces metadata:reloaded / does not announce when nothing was published.
  • Updatedflow-hot-reload.test.ts fake service (metadata → protocol source).
  • Green locally: @objectstack/service-automation 231/231, @objectstack/runtime 447/447; eslint clean.

Verification (end-to-end, clean instance, no restart)

On a fresh showcase (:3210):

  1. Authored a record-triggered flow showcase_pubtest as a draft in a writable base package.
  2. Pre-publish update of a showcase_task → flow did not fire (negative control — still a draft).
  3. POST /packages/:id/publish-draftswithout restarting → flow became active; response carried no rebindError.
  4. Post-publish update → flow fired (temporary process.stderr.write probe in AutomationEngine.execute, since logger.info is suppressed and sys_automation_run only records suspended runs). Probe removed before commit.

🤖 Generated with Claude Code

… a restart
Follow-up to #2560 (cold-boot flow binding). A flow published while the server
runs — author a record-triggered automation in the Studio, publish it,
immediately update a matching record — did not fire; its trigger only bound on
the next restart.
Two gaps, both fixed:
1. The publish path fired no rebind signal. The runtime dispatcher now announces
'metadata:reloaded' after a successful POST /packages/:id/publish-drafts — the
same signal a dev artifact reload fires — so boot-cached consumers re-sync.
2. The runtime re-sync read the wrong source. The automation service's
'metadata:reloaded' re-sync pulled metadata.list('flow'), which returns 0 in a
real running server; it now reads protocol.getMetaItems({type:'flow'}) — the
same flattened view #2560's cold-boot bind uses — keeping teardown of removed
flows. A failed/unavailable protocol read is a no-op and never tears down live
flows.
Verified end-to-end on a clean instance: authored a record-triggered flow in a
writable package, published it without restarting, then updated a matching record
and observed the flow fire (before the fix it did not). New regression tests:
flow-publish-rebind.test.ts (re-sync binds a post-boot flow, tears down a removed
one, reads the protocol not metadata.list, and never tears down on a failed read)
plus two http-dispatcher.test.ts cases (publish fires / does not fire the hook).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercelBot commented Jul 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 4, 2026 12:47pm

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling size/l labels Jul 4, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/runtime, packages/services.

21 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/cloud-artifact-api.mdx(via packages/runtime)
  • content/docs/concepts/implementation-status.mdx(via @objectstack/runtime)
  • content/docs/concepts/north-star.mdx(via packages/runtime)
  • content/docs/concepts/packages.mdx(via @objectstack/runtime)
  • content/docs/guides/api-reference.mdx(via @objectstack/runtime)
  • content/docs/guides/authentication.mdx(via @objectstack/runtime)
  • content/docs/guides/cloud-deployment.mdx(via @objectstack/runtime)
  • content/docs/guides/deployment-vercel.mdx(via @objectstack/runtime)
  • content/docs/guides/driver-configuration.mdx(via @objectstack/runtime)
  • content/docs/guides/hook-bodies.mdx(via @objectstack/runtime)
  • content/docs/guides/packages.mdx(via @objectstack/runtime, packages/services)
  • content/docs/guides/plugin-chatbot-integration.mdx(via @objectstack/runtime)
  • content/docs/guides/production-readiness.mdx(via @objectstack/runtime)
  • content/docs/guides/runtime-services/audit-service.mdx(via packages/services)
  • content/docs/guides/runtime-services/index.mdx(via packages/services)
  • content/docs/guides/runtime-services/settings-service.mdx(via packages/services)
  • content/docs/guides/single-project-mode.mdx(via @objectstack/runtime)
  • content/docs/protocol/objectos/http-protocol.mdx(via @objectstack/runtime)
  • content/docs/protocol/objectos/i18n-standard.mdx(via packages/services)
  • content/docs/protocol/objectos/index.mdx(via @objectstack/runtime)
  • content/docs/protocol/objectos/lifecycle.mdx(via @objectstack/runtime)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang