Skip to content

feat(workflows): add heartbeat config contract - #2229

Merged
flora131 merged 3 commits into
bastani-inc:mainfrom
morgan-coded:feat/workflow-heartbeat-config
Aug 14, 2026
Merged

feat(workflows): add heartbeat config contract#2229
flora131 merged 3 commits into
bastani-inc:mainfrom
morgan-coded:feat/workflow-heartbeat-config

Conversation

@morgan-coded

@morgan-coded morgan-coded commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Stack for #1975

Merge bottom to top; each PR is based on the one below it.

PR Slice
top #2383 builtin heartbeat cadences
#2379 terminal cleanup and restart recovery
#2377 scheduling and queued parent delivery
bottom #2229you are here authoring contract and event payload

Base of the stack is main. #2377, #2379 and #2383 are linked as GitHub stack #2380. #2229 cannot join it because its head branch lives on a fork, so this table carries the full chain.


Workflows have no authored heartbeat cadence or typed event contract for periodic parent alignment checks. This first slice adds heartbeatIntervalMinutes with a 15-minute default, explicit 0 disable behavior, finite non-negative validation, and a five-field event payload with identity keyed by runId plus scheduledAt — no goal field, per your amendment. Scheduling/delivery and terminal cleanup/recovery stay out of this slice and will follow separately; the three-slice design is recorded in specs/2026-08-06-workflow-heartbeats.md. docs/workflows.md and the workflows README carry the parameter, minute units, default, 0 semantics, and an example, each stating that a positive interval does not deliver heartbeats until the scheduler slice lands — say the word if you would rather hold the user-facing docs until then. Terminal evidence follows in a comment below. Part of #1975


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Greptile Summary

This change adds workflow heartbeat authoring configuration, a public heartbeat event contract, and documentation for the resolved default and disable behavior. Public-package verification confirmed that omitted intervals resolve to 15 minutes, explicit zero is retained, invalid numeric values are rejected, and the required package-root exports are available.

Confidence Score: 5/5

Safe to merge; no blocking failure remains.

No accepted blocking findings remain. The public workflow package contract was exercised successfully for defaulting, explicit disable behavior, invalid-value rejection, and package-root exports.

T-Rex T-Rex Logs

What T-Rex did

  • Ran the heartbeat authoring E2E script against the public package interface and ran the heartbeat contract tests; both passed with exit code 0.
  • After the package-root export, the authored script passed all required authoring-contract tests with exit code 0.
  • The public package heartbeat interface provides the heartbeat default and authoring behavior documented for workflow authors.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (6): Last reviewed commit: "refactor(workflows): colocate heartbeat ..." | Re-trigger Greptile

Copilot AI lite review requested due to automatic review settings August 7, 2026 00:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the slice-1 “heartbeat” authoring and contract surface to @bastani/workflows: a validated heartbeatIntervalMinutes option with a default, plus a typed custom event payload/identity contract, with accompanying spec/docs/tests. This aligns with #1975 while explicitly deferring scheduler/delivery + terminal cleanup to later slices.

Changes:

  • Added heartbeatIntervalMinutes to workflow authoring with defaulting (15), explicit 0 disable semantics, and non-negative finite validation.
  • Declared the workflows:workflow-heartbeat event contract (payload + identity types/constants) for later scheduling/delivery slices.
  • Added an RFC/spec, user-facing docs updates, and unit contract tests covering defaults/validation/immutability and event shape.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
test/unit/workflow-heartbeat-contract.test.ts Adds unit contract coverage for authoring default/validation/freeze behavior and the heartbeat event payload/identity shape.
specs/2026-08-06-workflow-heartbeats.md Introduces the three-slice RFC/spec describing goals, payload amendment, slice boundaries, and follow-up work.
packages/workflows/src/shared/workflow-authoring-types.ts Extends the authored workflow spec type with optional heartbeatIntervalMinutes.
packages/workflows/src/shared/authoring-contract-ui.ts Extends the compiled WorkflowDefinition contract with resolved heartbeatIntervalMinutes: number.
packages/workflows/src/extension/lifecycle-notifications.ts Declares the heartbeat custom type constant plus payload/identity interfaces alongside existing lifecycle notification contracts.
packages/workflows/src/authoring/workflow.ts Implements defaulting + validation and stamps the resolved heartbeatIntervalMinutes onto the frozen workflow definition.
packages/workflows/README.md Documents the new authoring parameter, units/defaults, and the fact that scheduling/delivery is not yet implemented in this slice.
packages/workflows/CHANGELOG.md Adds an Unreleased entry documenting the new authoring option and event contract (and clarifying that scheduling/delivery is out of scope here).
packages/coding-agent/docs/workflows.md Updates user-facing workflow docs with the new parameter, semantics, and an example, including “authoring-only” caveat for this slice.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@morgan-coded

Copy link
Copy Markdown
Contributor Author

Results from the bun -e authoring demo and npx vitest run test/unit/workflow-heartbeat-contract.test.ts:

omitted    -> heartbeatIntervalMinutes = 15
0          -> heartbeatIntervalMinutes = 0
30         -> heartbeatIntervalMinutes = 30
0.5        -> heartbeatIntervalMinutes = 0.5
-1         -> TypeError: workflow: heartbeatIntervalMinutes must be a non-negative finite number
NaN        -> TypeError: workflow: heartbeatIntervalMinutes must be a non-negative finite number
Infinity   -> TypeError: workflow: heartbeatIntervalMinutes must be a non-negative finite number

 RUN  v4.1.10 /Users/morgan/oss-workbench/repos/atomic-1975


 Test Files  1 passed (1)
      Tests  8 passed (8)
   Start at  19:23:34
   Duration  2.59s (transform 1.47s, setup 2.38s, import 34ms, tests 4ms, environment 0ms)

Live heartbeat delivery evidence follows with the scheduler slice.

@flora131

Copy link
Copy Markdown
Collaborator

Hi @morgan-coded, thanks for your patience, and sorry for the delay. We have been working through a larger refactor and the pi 0.84.1 dependency upgrade.

Since your last update, the branch has fallen behind and now conflicts with current main. Could you merge or rebase the latest main and resolve the conflicts?

Please also address Greptile's public API finding by exporting the heartbeat runtime constant and event types from @bastani/workflows, with a package-root consumer import test. Once those changes are in and CI is fresh, we can take a deeper look.

Please let us know if you have any questions.

@morgan-coded

Copy link
Copy Markdown
Contributor Author

Merged the latest main and resolved the changelog conflict. DEFAULT_WORKFLOW_HEARTBEAT_INTERVAL_MINUTES, WORKFLOW_HEARTBEAT_CUSTOM_TYPE, and the heartbeat event types (WorkflowHeartbeatEvent, WorkflowHeartbeatEventDetails, WorkflowHeartbeatIdentity) now export from the @bastani/workflows package root, with a package-root consumer import test covering the runtime values and the type surface. Fresh CI is green on the new head.

@flora131

Copy link
Copy Markdown
Collaborator

Thanks @morgan-coded! Is it cool if I take over the rest of the scope of the heartbeat functionality after this part you created we merge? I got an urgent request for it and wanted to make some changes as I go to the scope so didn't want to cause confusion. Thank you for getting it this far along.

@morgan-coded

Copy link
Copy Markdown
Contributor Author

Of course — take it from here. The #2229 contract should drop straight in as a base, and feel free to reshape any of it as the scope evolves. Thanks for the heads-up.

morgan-coded and others added 3 commits August 14, 2026 09:58
Move DEFAULT_WORKFLOW_HEARTBEAT_INTERVAL_MINUTES next to the heartbeat custom
type and event interfaces so slice 2 imports one contract module, and drop the
heartbeat re-export from lifecycle-notifications, which owns an unrelated event.
The contract test now imports the contract directly and pins the exported
default against the literal 15.

Co-authored-by: morgan-coded <256248948+morgan-coded@users.noreply.github.com>
Assistant-model: Claude Opus 5
@flora131
flora131 force-pushed the feat/workflow-heartbeat-config branch from 849702c to 9097e18 Compare August 14, 2026 16:59
@flora131
flora131 merged commit f940c75 into bastani-inc:main Aug 14, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants