Skip to content

feat(runtime): deferred-dispatch admission bound per ADR 0015 - #56

Merged
ThomasK33 merged 2 commits into
mainfrom
issue-44-admission-bound
Aug 27, 2026
Merged

feat(runtime): deferred-dispatch admission bound per ADR 0015#56
ThomasK33 merged 2 commits into
mainfrom
issue-44-admission-bound

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Implements the deferred-dispatch Admission Bound decided by ADR 0015 (merged in 984d094). Closes #44.

Runtime

  • RuntimeOptions.MaxDetached — per-instance cap on admitted-but-incomplete deferred dispatches. Required positive under DispatchDeferred (constructor validation, the DetachTimeout precedent); DefaultRuntimeOptions() sets 1024; sizing guidance lives on the option's GoDoc. Everything a delivery retains counts: running tails, parked queue/debounce waiters, concurrent slot-waiters — and capacity frees only when the tail goroutine returns, so stalled cleanup still counts as retention.
  • RuntimeOptions.MaxDetachedPerTenant (0 = disabled) — a per-installation ceiling keyed on ADR 0006's (adapter, tenant) identity, through the same rejection path (a ceiling, not a reservation). Per-tenant counters are garbage collected at zero. An empty tenant is a countable key, not an escape.
  • Reject-with-signal, before ack and before dedupe-mark: at the cap, dispatch fails fast with the new sentinel ErrAdmissionRejected before any State work — the delivery is never marked in Event Identity, so the platform's retry is not deduped away (the ADR 0002/0003 qualification recorded in ADR 0015 §1).
  • Shutdown closes admission: a delivery racing Shutdown is rejected with the same signal instead of being admitted into a runtime about to cancel its work.
  • Observability: new admission_rejected observation (adapter + tenant attrs) and admission-rejected terminal dispatch outcome.

Shape-aware adapter mappings (ADR 0015 §1)

Shape Platform redelivers? Response
Slack Events API callback yes 503 (retry-inducing; redelivery covers the event)
Slack slash command no 200 + truthful busy message (the shape's ack body renders as an ephemeral message to the invoker)
Slack block_actions no (ack body not rendered) 503 — Slack surfaces the failed delivery as a visible warning on the component; rejection stays observable
Linear webhook yes 503 (retry-inducing)

Hardening tests — the five named failure modes from the #54 review history

  1. Slot release on errored preludesTestAdmissionSlotReleasedOnErroredAndResolvedPreludes (errored AcquireLock preludes and synchronously-resolved ignored events all return capacity).
  2. Slot held until goroutine return (stalled cleanup)TestAdmissionSlotHeldUntilTailGoroutineReturns (handler returned, ReleaseLock stalled → slot still held; frees when the goroutine returns).
  3. Shutdown admission closeTestAdmissionClosedOnShutdown.
  4. Negative/empty-tenant validationTestAdmissionOptionValidation (MaxDetached <= 0 and MaxDetachedPerTenant < 0 rejected under deferred; ignored under sync) + TestAdmissionPerTenantCeilingKeysOnInstallation (empty tenant is a countable installation key).
  5. Per-tenant counter GCTestAdmissionPerTenantCounterGC (entries exact while in flight, zero after release; via a test-only accessor).

Plus: TestAdmissionRejectsAtMaxDetachedWithoutDedupeMark (sentinel surfaced, observation/outcome emitted, rejected Event Identity handled normally once capacity frees), per-strategy retention pins for queue waiters and concurrent slot-waiters, and adapter mapping tests for all four shapes (Slack ×3, Linear end-to-end through a saturated deferred runtime).

Docs (in scope per the issue contract)

  • CONTEXT.md glossary: Admission Bound.
  • ADR 0012: status note recording the three supersessions by ADR 0015.
  • ADR 0015: Status → Accepted.
  • Deferred-dispatch how-to: MaxDetached bullet; runtime GoDoc comments updated where ADR 0015 superseded ADR 0012 phrasing; hello-world example sets MaxDetached.

Additive API only; no new dependencies. Note: deferred configurations built without DefaultRuntimeOptions() must now set MaxDetached — deliberate per ADR 0015 ("no unbounded production default survives this ADR").

Validation

  • mise run vet — clean across all workspace modules.
  • GOFLAGS=-race mise run test — all modules ok (root, adapters, examples, state/memory, state/nats, state/postgres, state/redis).

Generated with mux • Model: anthropic:claude-fable-5 • Thinking: xhigh

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5199976541

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread runtime.go Outdated
@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: 5199976541

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: daa7113e68

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: daa7113e68

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 merged commit a1a8602 into main Aug 27, 2026
1 check passed
@ThomasK33
ThomasK33 deleted the issue-44-admission-bound branch August 27, 2026 21:58
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.

runtime: consider a deferred-dispatch admission bound (goroutine per accepted event)

1 participant