Skip to content

feat(core): add scheduledExecution subject and events - #323

Open
sol-duara wants to merge 1 commit into
cdevents:mainfrom
Sol-Duara-Inc:feat/scheduledexecution-subject
Open

feat(core): add scheduledExecution subject and events#323
sol-duara wants to merge 1 commit into
cdevents:mainfrom
Sol-Duara-Inc:feat/scheduledexecution-subject

Conversation

@sol-duara

Copy link
Copy Markdown

Changes

Adds a scheduledExecution subject to the Core vocabulary, with created, modified, canceled, triggered and missed predicates.

A scheduledExecution is a registered intent to enqueue a target execution — a build, a deployment, a change window opening — at a future time. It covers the lifecycle before enqueueing: the schedule is registered, possibly changed, and then either fires, is canceled, or does not fire at all.

Why a new subject

This came from an operator running scheduled deployments who needed the event stream to answer six questions: who scheduled a build or deployment, whether the schedule was subsequently changed, who changed it, whether it was canceled, who canceled it, and whether it actually fired and when.

The existing queued predicates cannot answer any of them. build.queued and the service deployment events represent work already accepted into an execution queue — the earliest moment the vocabulary can currently express. A schedule registered today to fire next Tuesday is invisible until it materializes as a queued execution, and by then the registration, every amendment to it, and any cancellation have left no trace.

Making the schedule itself a subject puts that history in the stream. triggered is the hand-off: the occurrence that subsequently produces the existing queued event for the target.

author on triggered

author is required when trigger.type is manual, and MUST NOT be present for any other value. The schema encodes both directions, and requires trigger.type so neither branch can be evaded.

The biconditional is the point. Because the absence of author is what tells a consumer that no actor fired the execution, a time-fired event must not carry one — attaching the schedule's creator there would misreport a weeks-old registration as a person running something today. A pipeline or an event is likewise not a person, so those values carry no author either.

Manual firing is ordinary, not an exception. A scheduler's "Run Now" is the normal way an author tests a schedule before trusting it to fire unattended. It is therefore an attribute of triggered rather than a separate predicate, which would rest on the premise that "Run Now" is unusual. Audit interest in off-schedule firing of a sensitive target is a consumer policy — filter on trigger.type and target — not a vocabulary distinction.

missed

missed is a live producer reporting that a scheduled execution did not fire. It distinguishes a schedule that never fired from an execution that fired and then failed; the latter is reported by the target's own events.

Emission is at the producer's discretion and the vocabulary sets no tolerance window. A normative threshold was considered and not taken: arrival time cannot be predicted accurately in a distributed system, so any threshold would encode a guarantee the transport cannot make. Producers know their own scheduling semantics, and consumers should read scheduledTime against the event's own timestamp rather than rely on a standard grace period.

A producer that was itself unavailable at scheduledTime emits nothing at all, including no missed. That gap is found by querying for the event that is absent, which is the same mechanism that detects any expected occurrence that never arrived.

Design decisions

Two times are carried, and both matter. scheduledTime is the intended time; context.timestamp is when the occurrence happened. On triggered, the difference between them is the on-time-versus-late record. The producing scheduler or controller is identified by context.source, which every CDEvent already carries, so no separate field names it.

author records attributed identity, not authenticated identity. It is an addressing key: the actor the producing system attributes the action to. Proving the actor is the producer's responsibility.

target carries a type alongside id and source, so consumers can route on the kind of thing scheduled, and so target references are shaped consistently across subjects. type is a free string — build, deployment, changeWindow — rather than a closed enum, so the subject is not coupled to a fixed list of schedulable things.

triggeredExecution is a field, not a link. Replacing it with a relation link to the enqueued execution was considered. Linking is optional in CDEvents and an event should be complete without it: a consumer reading a triggered event should not have to consult a second mechanism to learn what was enqueued, particularly when the scheduler knows exactly what it just enqueued and can say so directly.

The subject is treated as a sequence of actions, not a definition. It was put to us that the lifecycle here is mostly definitional and might not warrant occurrence events. Registering a schedule is an action taken at a point in time by an identifiable actor, and it produces something that did not exist beforehand; canceling it removes that thing. Each is an occurrence an auditor may need to account for, and each is reported as it happens.

No field for event publication time. Publication timing is a property of the transport carrying the event, not of the thing that happened. The intended time and the occurrence time are both present already.

No attempt identifier. A retry is a new occurrence with its own identity. This is also not specific to scheduledExecution; if attempt identity is wanted, it belongs in the context for every subject.

The trigger object is reused byte-identically from the Testing vocabulary, including its existing schedule value. No new common objects are introduced.

Out of scope

  • The authorization decision to create or amend a schedule. approval already covers accountable authorization decisions. A schedule requiring sign-off is two occurrences.
  • Whether a fired execution is permitted to proceed. Control-plane behavior. These events report that the schedule fired.

Notes on this change

Event versions start at 0.1.0-draft.

schemas/_defs/ entries and x-cdevents-semantics are not included here. The predicate definitions this subject would need overlap with those already being added by #319 and with further subjects we are proposing; adding them here would collide. We will follow up with them once #319 lands.

Submitter Checklist

As the author of this PR, please check off the items in this checklist:

  • Has the primer doc been updated if a design decision is involved — no new concept is introduced; this applies existing vocabulary patterns
  • Have the JSON schemas been updated if the specification changed
  • Has spec version and event versions been updated according to the versioning policynew events start at 0.1.0-draft; the spec version is unchanged
  • Meets the CDEvents contributor standards

A scheduledExecution is a registered intent to enqueue a target
execution at a future time. It covers the lifecycle before enqueueing:
the schedule is registered, possibly amended, and then either fires, is
canceled, or does not fire at all.

The existing queued predicates represent work already accepted into an
execution queue, which is the earliest moment the vocabulary can express
today. A schedule registered now to fire next week is invisible until it
materializes as a queued execution, by which point the registration,
every amendment, and any cancellation have left no trace. Making the
schedule a subject records who scheduled an execution, whether and by
whom it was changed or canceled, and whether it fired and when.

Five predicates: created, modified, canceled, triggered, missed.
triggered is the hand-off that subsequently produces the target's own
queued event; missed distinguishes a schedule that never fired from an
execution that fired and then failed.

On triggered, author is required when trigger.type is manual and MUST
NOT be present when it is schedule: the absence of author is what tells
a consumer that elapsed time, rather than a person, fired the execution.
trigger.type is required so neither branch can be evaded.

The trigger object is reused byte-identically from the Testing
vocabulary, including its existing schedule value. No new common objects
are introduced. Event versions start at 0.1.0-draft.

Signed-off-by: Dadisi Sanyika <dadisi@solduara.com>
@sol-duara
sol-duara requested a review from a team as a code owner July 29, 2026 18:12
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.

1 participant