Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ _Avoid_: Lock implementation detail
A per-**Thread** coordination guard that prevents concurrent handler execution for the same conversation.
_Avoid_: Event lock, adapter lock, handler lock

**Lock Scope**:
The **Runtime Options** choice of what key the **Thread Lock** guards: a single **Thread** (default) or the Thread's whole channel where the platform's model requires channel-wide serialization.
_Avoid_: Lock granularity flag, channel lock

**Lock Lease**:
A token-owned **Thread Lock** record that can only be released or extended by its current owner.
_Avoid_: Untokened lock, delete-only lock
Expand Down Expand Up @@ -416,7 +420,8 @@ _Avoid_: Full platform schema, strict external SDK model
- Default **Runtime Options** use a 24 hour dedupe TTL and a 2 minute **Thread Lock** TTL.
- **Runtime Options** TTL values must be positive.
- **Runtime Options** include a **Concurrency Strategy** that defaults to drop.
- The runtime implements the drop (default) and queue **Concurrency Strategy** values; burst, debounce, concurrent, lock-scope, and force/steerability remain reserved for future slices.
- The runtime implements the full upstream-aligned **Concurrency Strategy** set: drop (default), queue, debounce, burst, and concurrent, plus a **Lock Scope** option (thread default, channel opt-in) and a force/steerability hook that preempts an in-flight handler by force-releasing its **Lock Lease** through an optional **Runtime State** capability.
- Debounce and burst coalesce on a configured interval and require deferred **Dispatch Mode**; concurrent takes no **Thread Lock** and is bounded by a configured maximum; skipped (superseded) events are always observable, never silent.
- A **Thread Lock** coordinates processing of distinct **Webhook Events** for the same **Thread**; it never deduplicates them, and what happens to a conflicting event is decided by the **Concurrency Strategy** (drop acknowledges and drops it; queue coalesces waiters per process and runs the most recent after the lock releases).
- A **Thread Lock** is represented as a **Lock Lease** with an ownership token.
- Releasing or extending a **Lock Lease** must verify the ownership token so an expired holder cannot affect a newer holder.
Expand Down
32 changes: 25 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,11 +518,31 @@ chat.RuntimeOptions{
}
```

Two concurrency strategies are implemented: `ConcurrencyDrop` (the default)
acknowledges and drops events that hit a locked thread, and `ConcurrencyQueue`
waits for the lock and runs only the most recent superseded follow-up, with
most-recent coalescing scoped per process (ADR 0012). Burst, debounce, force,
and concurrent strategies remain proposed in ADR 0012 and are not implemented.
The runtime implements the full upstream-aligned strategy set (ADR 0012):

- `ConcurrencyDrop` (default): a lock conflict is acknowledged and dropped.
- `ConcurrencyQueue`: the newest follow-up waits for the in-flight handler;
superseded follow-ups are observable, never silent.
- `ConcurrencyDebounce`: each new event resets a `DebounceInterval` timer; only
the final event in a quiet period dispatches. Requires deferred dispatch.
Coalescing (like queue supersession) is per runtime instance; instances
sharing a state are serialized by the thread lock, not coalesced.
- `ConcurrencyBurst`: events collect for `DebounceInterval` on an idle scope,
then the whole batch dispatches — in the order events joined the window —
under one lock hold and a fresh `DetachTimeout` that starts when the window
closes. Requires deferred dispatch.
- `ConcurrencyConcurrent`: no thread lock at all; every event dispatches in its
own execution, bounded by `MaxConcurrent`.

`LockScope` chooses what the lock guards: per thread (default) or per channel
(`LockScopeChannel`) for platforms whose model needs channel-wide ordering.

`OnLockConflict` is the force/steerability hook: on a lock conflict it can
preempt the in-flight work. A local handler is cancelled with
`chat.ErrPreempted` and awaited, after which the new delivery acquires the
released lock; a lease held by another runtime instance (or orphaned) is
force released through the optional `LockForcer` state capability instead. It
requires deferred dispatch and the drop or queue strategy.

Thread locks use token-owned lock leases. Release and extend operations must
verify the token so an expired handler cannot release or extend another
Expand Down Expand Up @@ -795,8 +815,6 @@ include:
interaction response needs
- no bundled metrics framework, exporters, or scrape endpoint (an optional no-op
`Observer` seam is provided; OpenTelemetry stays out of the core import graph)
- no burst, debounce, force, or concurrent lock-conflict strategies (drop and
queue are implemented)
- no built-in HTTP server or router integrations
- no adapter marketplace/package conventions

Expand Down
Loading