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

  • New flow-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.
  • New http-dispatcher.test.ts cases: publish-drafts announces metadata:reloaded / does not announce when nothing was published.
  • Updated flow-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-drafts without 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

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 4, 2026 12:47pm

Request Review

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

github-actions Bot commented Jul 4, 2026

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 free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant