devinside.Marcin Borecki Ideas. Systems. Evidence.
← The notebook

Engineering

When an Event Starts an Agent: Delivery, Delay and Ordering Contracts

A transactional event ledger separates delivery from valid work, testing duplicates, object versions, expiry, supersession and overlap before an execution attempt.

Explore the mechanism ↓
Editorial ink and watercolor illustration for Delivery is not permission to execute

START WITH THE MECHANISM

Interactive companion and laboratory update: 12 November 2026. The editorial date places the topic on the timeline; this current explanation and its measured evidence retain their actual preparation and execution dates.

THE FULL INVESTIGATION

When an Event Starts an Agent: Delivery, Delay and Ordering Contracts

Editorial context: 30 April 2026 · Prepared and updated: 12 November 2026
Dates and technology context

This is a retrospective editorial timeline. Topic context: 30 April 2026. First publicly available: 12 November 2026. Current text, visuals and laboratory revisions were prepared on 12 November 2026.

Duplicate/overlap/stale/superseded matrix, four competing deliveries,27 shared checks, Agents.AI1.28.0 and MEAI11.0.0 are12Nov2026 evidence. Preview beforeApr2026.

Prepared on 12 November 2026. This laboratory uses a local SQLite event/job ledger and a controlled receiver. It does not connect to a message broker or cloud scheduler. Its agent adapter is real Microsoft Agent Framework with a scripted provider, while event admission remains deterministic application code.

An event arriving is not the same as a new task becoming valid. The event may be a duplicate, describe an old object version, have waited past its useful lifetime or overlap work already in progress. Starting another agent run for every delivery can turn ordinary transport behavior into repeated and conflicting business work.

The important decision therefore comes before model reasoning: should this event create executable work now, under the current object state and application policy?

This article implements that decision in a small durable ledger. It gives events stable identities, binds them to object versions, records explicit admission outcomes and rechecks the relevant conditions before execution. It tests both sequential and concurrent duplicate delivery, reversed arrival order, expiry, permission revocation and supersession.

The example shares code with the session-state and restart laboratories, but asks a different question. It does not investigate what an agent remembers or how to confirm an effect after a lost reply. It investigates whether a delivered signal is still a valid reason to attempt the effect at all.

The result is a concrete application contract. It is not a claim that a particular broker provides exactly-once behavior, or that a scheduler's tick is automatically a unique business obligation.

An event is a claim about a moment in a changing system

01 / See the idea

The envelope names several different facts

The envelope names several different facts. A newly delivered envelope can still describe obsolete work. Its identity, object version and validity rules answer different questions and must remain separate.

A newly delivered envelope can still describe obsolete work. Its identity, object version and validity rules answer different questions and must remain separate.

Interpretation and evidence
  • Do not renew validity by redelivering.
  • Define the expiry edge explicitly.
  • Version the interpretation of durable state.
Shared AI04 correctness.json and measurement-1..3.json; no production or hosted-model outcome.

The fixture's trigger record contains an event ID, object ID, object version, expiry, payload and workflow version. Each field has a different job.

The event ID distinguishes repeated delivery of one envelope from another event. The object ID identifies the domain record. The object version states which revision the event concerns. Expiry defines how long the proposed work remains eligible. The payload preserves what the event asks the workflow to process. The workflow version identifies the supported interpretation of that envelope.

These fields are not interchangeable. A new delivery timestamp does not make an old event new. A new event ID does not make work on an obsolete object version useful. A matching object ID does not establish that the same payload was approved twice.

The application-owned type is intentionally small:

public sealed record Trigger(
    string Id, string ObjectId, long Version,
    long ExpiresAt, string Payload,
    string WorkflowVersion = "1");

Time in this fixture is a controlled integer supplied to the operation. It is not a benchmark duration or a real scheduler's timestamp. The tests choose values that make the expiry boundary deterministic, including equality at the deadline.

A real service would need to define its clock, timestamp origin and tolerance for delay. The fixture establishes the application rule once a time value is available; it does not claim to solve clock synchronization across hosts.

Distinguish a duplicate from an identity conflict

When an event ID already exists, the store compares the meaningful envelope fields. If object, version, expiry, payload and workflow version match, the delivery is classified as Duplicate. If the identity is reused with different content, the result is IdentityConflict.

That distinction matters. Treating every repeated ID as harmless could hide a producer bug or an attempt to redefine an already recorded operation. Treating every repeated ID as new work could create repeated effects.

The duplicate check is performed inside a database transaction. The event ID is also the primary key of the durable job table, so the decision is backed by persisted identity rather than a process-local collection that disappears on restart.

The fixture first checks the object's tenant scope, so a caller outside that scope is not allowed to use duplicate detection as an alternative route into the record. The trusted tenant is supplied by the test application; it is not accepted from model-generated prose.

The test sends the same envelope again and then changes its payload while preserving the ID. It expects Duplicate in the first case and IdentityConflict in the second. Those outcomes are explicit and separate from whether an earlier job ultimately completed.

An application can use the distinction to decide what happens next. A duplicate may return the recorded state. A conflict should be investigated or rejected according to the producer contract. Neither should automatically invoke the agent again.

Current object version decides whether old work still applies

02 / See the idea

Arrival order changes the trace, not eligibility

Arrival order changes the trace, not eligibility. With the domain object fixed at version2, both controlled arrival orders reject version1and admit version2. This is a latest-applicable-state policy, not a rule for every event-sourced history.

With the domain object fixed at version2, both controlled arrival orders reject version1and admit version2. This is a latest-applicable-state policy, not a rule for every event-sourced history.

Interpretation and evidence
  • Assert the final invariant, not a lucky arrival order.
  • Keep domain policy explicit.
  • Do not discard historical events where every fact matters.
Shared AI04 correctness.json and measurement-1..3.json; no production or hosted-model outcome.

The domain object is stored independently of the event. It has its own version, permission state and value. Admission checks the event's version against the current object version before creating Pending work.

If an event for version one arrives while the object is already version two, the fixture records Stale. It does not ask the model whether the old request still sounds reasonable. That decision belongs to the declared workflow policy.

The test examines two arrival orders for the same pair of events while the domain object is fixed at version two. In one order, the version-one event arrives first; in the other, the version-two event arrives first. The final classification is the same: version one is Stale and version two is Pending.

The observed traces are different sequences, but they lead to the same relevant state. This is a stronger and more useful assertion than expecting arrival order itself to be stable.

The policy is intentionally conservative. Some domains may need to process every historical event, while others need only the latest state. This example implements a latest-applicable-version workflow. It must not be copied into an event-sourced accounting process where discarding old facts would lose required history.

Naming that domain assumption is part of the contract. A generic promise to handle out-of-order messages does not specify which work the application is allowed to omit.

Admission is not the final authorization to execute

03 / Watch the mechanism

Recheck before the effect begins

Recheck before the effect begins. The test changes state between admission and claim. Superseded, expired or denied work is refused before an execution attempt, while later in-flight changes remain outside this guarantee.
Enlarge diagram

Static view. Play to see how the mechanism unfolds.

The test changes state between admission and claim. Superseded, expired or denied work is refused before an execution attempt, while later in-flight changes remain outside this guarantee.

Interpretation and evidence
  • Admission does not freeze the world.
  • Count attempts separately from delivery.
  • Name the boundary where authority was checked.
Shared AI04 correctness.json and measurement-1..3.json; no production or hosted-model outcome.

An event can be valid when admitted and invalid when a worker later claims it. The object may change, the permission may be revoked or the expiry may pass during the wait.

The Claim method therefore reloads the object and rechecks these conditions inside its own transaction. A Pending job becomes Executing only after that check. If it is rejected, its attempt count remains unchanged.

This is important for interpreting operational metrics. A delivered event, an admitted job and an execution attempt are different counts. A system can correctly receive many events while attempting fewer effects because some became stale or expired.

The test changes the object's version after admission but before execution. The old Pending job becomes Superseded and the receiver remains empty. A separate case revokes permission before claim; the job becomes Denied with zero attempts.

The check occurs at the execution-claim boundary. It is not a guarantee that an external action can be recalled if the object changes after the claim has committed. A production system needs to understand the interval between authorization and the destination's acceptance, especially when consequences are irreversible.

The reference preserves that limitation rather than implying that one database check freezes the whole world. It establishes what the application knew and accepted at a specific boundary.

Expiry needs a precise edge

The fixture treats an event as expired when its expiry value is less than or equal to the supplied current time. The test includes an event whose expiry equals now, so the boundary is explicit rather than dependent on a convenient example well past the deadline.

Another test admits a job just before expiry and attempts to claim it at the expiry value. It is rejected at execution. This demonstrates why admission and dispatch checks cannot be collapsed into one earlier decision.

Expiry is a business policy in this example. It says the workflow should no longer start that work. It is not evidence that the event never happened or that an already started external effect can be undone.

A late event may still be useful for auditing or diagnosis even when it should not create a new action. The job ledger records its terminal classification so the application can explain why it did not proceed.

The expiry value also should not be confused with a transport retention setting. A broker may retain a message according to its own configuration, while the application considers the described work obsolete much earlier or later. Since this fixture uses no broker, it makes no claim about a particular service's retention, delay or redelivery semantics.

The article's contribution is to make the application-level decision testable before a transport is selected.

Scheduled overlap is a policy, not a timer defect

Suppose a scheduled check produces a new event while equivalent work for the same object version is already Pending, Executing or Unknown. Starting another agent run may add cost without adding useful information, or it may produce competing effects.

The fixture chooses to classify same-version overlap explicitly. A second event with a different event ID but the same object and version is not a transport duplicate. It is a separate signal whose work overlaps the existing obligation.

The admission test therefore distinguishes Duplicate from Overlap. The former repeats one identity; the latter introduces a new identity that conflicts with the chosen execution policy.

This distinction helps explain scheduled work. A timer can fire correctly while the application correctly declines to start another task. Counting that event as a scheduling failure would misdescribe the system. Counting it as completed work would be equally misleading.

The fixture does not run a real timer. It supplies the overlapping event in a controlled sequence. That establishes the decision rule without relying on a wall-clock race. A later host integration would need to verify actual trigger delivery and shutdown behavior separately.

The chosen policy may be too strict for a different domain. Independent operations could be allowed in parallel, or later ticks could update a pending request. Those are legitimate alternatives, but they require a clear statement of which effects may coexist and how the final state is determined.

Supersession applies before an effect begins

05 / See the idea

Pending replacement differs from uncertain effects

Pending replacement differs from uncertain effects. A newer desired version can replace unstarted work, but it cannot prove that an earlier effect did not happen. The fixture keeps that uncertain operation active and blocks another execution.

A newer desired version can replace unstarted work, but it cannot prove that an earlier effect did not happen. The fixture keeps that uncertain operation active and blocks another execution.

Interpretation and evidence
  • Do not use supersession to erase an effect.
  • Separate queue policy from recovery.
  • Make the availability cost of conservative blocking visible.
Shared AI04 correctness.json and measurement-1..3.json; no production or hosted-model outcome.

When a newer applicable event is admitted, the reference marks older Pending jobs for the same object as Superseded. That prevents obsolete work from starting merely because it entered the queue earlier.

The word Pending matters. An operation whose effect may already have occurred cannot be safely erased by changing a label to Superseded. Executing and Unknown states retain obligations that need separate resolution.

The shared recovery fixture demonstrates the boundary. An earlier operation with an unknown receiver outcome blocks a later execution, even after the object advances to a newer version. The later job's claim returns Overlap and does not increment its attempt count.

This can reduce availability, which is a real consequence of the chosen policy. It avoids guessing that the earlier effect is irrelevant. A more advanced system might resolve or compensate the earlier operation and then proceed, but that behavior is not implemented here.

The test therefore distinguishes two forms of replacement. Pending work can be superseded because it has not crossed the execution boundary. An uncertain effect cannot simply be superseded because the application no longer prefers it.

That distinction is easy to lose in an agent interface where a new conversation feels like a fresh start. Durable state belongs to the underlying obligation, not to the latest conversational focus.

Test duplicate admission with actual competing calls

04 / See the idea

Four competing duplicate deliveries

Four competing duplicate deliveries. Four actual competing calls use the same envelope and database. The winner can vary, but the observed invariant is one admitted job and three duplicate classifications.

Four actual competing calls use the same envelope and database. The winner can vary, but the observed invariant is one admitted job and three duplicate classifications.

Interpretation and evidence
  • Avoid asserting which thread wins.
  • Persist identity rather than relying on process memory.
  • A small correctness race is not a load-capacity test.
Shared AI04 correctness.json and measurement-1..3.json; no production or hosted-model outcome.

Sequential replay is not the only duplicate case in the suite. Four tasks call admission with the same envelope against the same SQLite fixture. The expected result is exactly one Pending admission and three Duplicate outcomes.

The order of those four returned statuses can vary. The assertion does not require a particular thread to win. It checks the invariant that only one durable job is admitted for the identity.

SQLite's transactional behavior and unique key provide the local coordination boundary. Microsoft documents that SQLite has one writer with pending changes at a time and that operations can encounter contention or timeout. The reference uses that local model; it does not claim a distributed lock across hosts. Microsoft.Data.Sqlite transactions.

The test is bounded to four calls, not a load generator. Its purpose is correctness under a small controlled contention case. The later replay timings use sequential calls and should not be interpreted as concurrent capacity.

If a production event receiver uses a different store, the admission invariant must be re-established for that store. A familiar method name such as insert-if-absent is not enough to prove the transaction boundaries and conflict behavior match the required contract.

Keep the agent behind the deterministic admission decision

The shared laboratory includes an actual ChatClientAgent tool roundtrip using Microsoft.Agents.AI 1.28.0 and Microsoft.Extensions.AI 11.0.0. Its provider is scripted and its tool reads the current domain record. The session test confirms that a new conversation can still obtain the updated object version. Pinned Agent Framework package.

Event admission does not call that provider to decide whether an envelope is a duplicate, stale or expired. Those rules are deterministic application policy. The agent can be invoked after the application establishes that work is eligible, but it should not grant itself permission to reinterpret a rejected trigger.

The present executable keeps the read-only agent test and durable effect test distinct. It does not claim that every state transition has been exercised through a live model. That is deliberate: the event contract should remain testable independently of uncertain planning behavior.

A later integrated agent could propose work based on the admitted event. Its executor would still need to preserve event identity, object version and authority at the point of action. The model's explanation would not replace the checks.

This separation makes a framework upgrade less likely to redefine the meaning of event delivery. The surrounding application continues to know which obligations exist and which signals were refused before they became attempts.

Read the executed decision table as a contract

The shared correctness run passed twenty-seven named checks. The event-specific results include the following:

Controlled condition Observed decision
First current event Pending
Exact repeated envelope Duplicate
Same ID, changed payload IdentityConflict
Different ID, same-version pending work Overlap
Old version against current object Stale
Old Pending job after object update Superseded at claim
Revoked permission before claim Denied, zero attempts
Expiry equal to now Expired
Unsupported workflow version UnsupportedWorkflow
Four competing identical deliveries One Pending, three Duplicate

The decision table does not count every refusal as an error. Several refusals are the intended behavior. The relevant question is whether the system made the decision required by the declared envelope and current state.

The tests preserve the difference between state and effect. A Superseded or Denied job has not created a receiver action in the examined scenario. An Unknown job represents a different problem and remains subject to reconciliation.

This makes the output useful for a future operator interface. A list of failed jobs would hide whether work was invalid, obsolete, overlapping or genuinely unsuccessful after an attempt. The application should preserve these reasons rather than flatten them into one generic exception category.

The measured replay path does not include a broker or a model

The integration owner measured two sequential local paths in three fresh processes. One performs one hundred duplicate admissions against an already recorded event. The other performs one hundred reconciliation calls against an already Completed job.

The duplicate-admission median was 29.5469 milliseconds per hundred calls, with process batch values from 29.3391 to 30.0120 milliseconds. Completed reconciliation had a median of 26.9909 milliseconds, with values from 26.8502 to 27.0349 milliseconds.

Each result retained one receiver effect. The timing does not include creating that effect, starting an agent, executing a model or delivering a broker message. The completed reconciliation path mainly reads and recognizes an existing terminal state; it is not the lost-acknowledgement recovery path.

The measurement also includes the local connection and transaction behavior of this implementation. It is not a pure in-memory dictionary lookup. That makes the result concrete, but it does not make it a throughput forecast for a deployed event service.

The host was shared, and only three process repetitions were collected. The numbers are process-average observations, not p95 latency or a service-level guarantee. Their role is to describe the tested replay boundary, while the correctness suite establishes the intended state decisions.

An event payload is data, not a new source of authority

The payload can describe useful work, but it does not supply the trusted tenant or override the current object's permission state. The application receives those conditions through its own controlled context and store.

This remains important when the event contains natural-language material intended for an agent. A sentence saying that an administrator approved the action is still payload content. It is not an authenticated approval merely because the model can read it.

The present fixture uses short synthetic strings, so it does not perform a prompt-injection evaluation. Its contribution is architectural: the admission decision does not delegate identity, expiry or object-version policy to the string being processed.

A future agent can use the payload to interpret the task within those boundaries. If interpretation requires a different scope or effect, the application should treat that as a new proposal requiring the appropriate checks, not as permission to rewrite the admitted envelope.

This also explains why an identity conflict is distinct from ordinary content variation. If the producer changes what an existing event means, the receiver needs to notice that change before the agent begins a new interpretation of it.

Backlog policy should be visible before the scheduler starts

After a period of downtime, a scheduler might deliver several signals close together. The application needs to decide whether each represents independent work, whether only the latest state matters, or whether some signals can be coalesced.

The fixture's policy favors current-version work and rejects overlap. That is one possible answer, not an implicit property of scheduling. A report should make the policy visible so an operator can understand why several delivered signals produced fewer attempted actions.

For a hypothetical inventory refresh, processing the latest state once may be appropriate. For a ledger of distinct purchases, omitting earlier events would be unacceptable. The transport can deliver both as messages, but their business semantics differ.

The design should therefore establish what the event identity represents before choosing a deduplication mechanism. Does it identify one occurrence, one desired state or one scheduled opportunity to inspect a state? Those choices determine whether Duplicate, Stale and Overlap are reasonable outcomes.

No live scheduler was exercised here. The controlled inputs allow those decisions to be tested without waiting for wall-clock ticks. A later scheduler integration should preserve the same policy and add evidence about actual delivery, shutdown and restart behavior.

Keep attempts and omissions in the same operational story

A dashboard that shows only executed jobs would hide the application decisions that prevented work from starting. A dashboard that counts every delivered event as an attempted task would overstate the work performed.

The fixture records admission and terminal states so a later report can distinguish those paths. Denied, Expired and Superseded can be correct decisions with zero attempts. Unknown belongs to an attempted operation whose outcome remains unresolved. Duplicate refers to repeated identity rather than a second effect.

These distinctions help an operator ask a useful next question. A high number of expired events might lead to investigating delivery delay or an unrealistic expiry policy. Identity conflicts might indicate a producer contract violation. Overlap might reflect a deliberately conservative policy or work taking longer than expected.

Those are hypotheses, not automatic diagnoses. The state counts identify where to look; they do not establish the cause by themselves. Preserving the classifications is still valuable because it prevents a generic failure count from concealing the mechanism the team needs to understand.

A useful event contract is explicit about what it omits

This reference has no cloud broker, actual timer host, dead-letter queue, distributed lease or multi-region store. It does not claim the scheduling or redelivery guarantees of Azure Service Bus or another service merely because those technologies could later transport the envelope.

It also does not solve every domain's ordering problem. The latest-applicable-version policy is suitable for this synthetic task, not for every event history. Some domains must preserve and process all events, while others can safely coalesce pending work. The policy must follow the meaning of the task.

Finally, the current checks occur before execution is claimed. A source change after that boundary may require destination-side version checking or another coordination mechanism. The fixture does not promise to recall an already in-flight effect.

These limitations make the next integration questions concrete. What identity does the broker preserve? What happens after host restart? Which clock defines expiry? Which store serializes admission? Can the destination confirm an effect? Which old work may be superseded, and which must be reconciled?

The event receiver becomes dependable when those questions have explicit answers. An agent can then participate in eligible work without being asked to invent the delivery semantics around it. The application remains responsible for deciding when a signal is a valid reason to act.

Source code and execution evidence

Download the complete lab, source record and raw execution results. This package supports the specific execution claims in this article. It is not a production certification.

THE AUTHOR

Marcin Borecki

Developer, entrepreneur and business angel. Writing about AI, software, data and the evidence behind technical decisions.

About the author →