Liking cljdoc? Tell your friends :D

Background Tool Jobs Test Matrix

Scope: spec/background-tool-jobs.allium

Goal: cover nominal, edge, and boundary behavior for tool-started background jobs, lifecycle tracking, terminal chat injection, and thread-scoped controls.

Coverage Map (spec behavior → tests)

  • Dual-mode tool result (sync vs background) → N1, N2, B1
  • job_id only for background starts → N1, N2
  • One background job per tool invocation → N2, E1
  • Globally unique job_id → E2, B2
  • Thread-scoped visibility/controls → N8, E8, E9
  • In-memory only tracking (no restart recovery) → E12
  • Cancel by user/agent → N6
  • Best-effort cancel (pending_cancel, may still complete) → N6, E5
  • Completion wins cancel race when already finished → E6
  • Terminal states only trigger injection → N3, E3
  • One synthetic assistant message per terminal job → N4, E4
  • Completion-time ordering across multiple terminal jobs → N5, B3
  • Turn-boundary injection + idle terminal triggers next boundary → N4, E7
  • At-most-once injection semantics → E4, B4
  • Payload constraints follow tool output limits → N7, E10, B5
  • Oversized payload writes temp file and message references it → N7, E10
  • list jobs default non-terminal set → N8
  • list jobs explicit status filtering → N9
  • inspect job in-thread success / cross-thread rejection → N10, E9
  • Manual retry unsupported → E11
  • Internal retryable LLM HTTP errors are internal-only (no external terminal injection) → E13
  • Terminal retention bounded to 20 per thread, evict oldest terminal, preserve non-terminal → B6, B7, B8

Nominal Tests

IDScenarioArrangeAssert
N1Synchronous tool completionTool invocation completes inlineResponse mode is synchronous; no job_id; no background job record
N2Background start responseTool starts background jobResponse mode is background; includes job_id + running; one job record created
N3Terminal status transitionRunning job reaches completed/failed/cancelled/timed_outJob status becomes terminal; completed_at and terminal payload recorded
N4Single terminal injectionTerminal job, turn boundary reachedExactly one synthetic assistant message appended for that job; turn triggered
N5Ordered multi-job injectionTwo+ jobs terminal before boundaryInjection order follows completion time oldest→newest
N6Cancel request (user + agent)Running job, cancel requested by each actor typeStatus moves to pending_cancel; cancellation request sent to tool runtime
N7Oversize payload pathTerminal payload larger than policy limitsPayload written to temp file; synthetic message includes temp file reference
N8Default list behaviorThread with mixed statuseslist jobs default returns only running + pending_cancel
N9Explicit status filterThread with mixed statuseslist jobs(statuses=...) returns only requested statuses
N10Inspect in-threadRequest inspect from originating threadFull job record returned

Edge Tests

IDScenarioArrangeAssert
E1Attempt second background job for same tool callSame tool_call_id starts job twiceContract violation/rejection; still at most one job for tool call
E2Duplicate job_id collisionAttempt create with existing job_idRejected; uniqueness invariant preserved
E3Non-terminal updates do not injectRunning/pending-cancel updates occurNo synthetic assistant message created
E4Duplicate emit attemptEmit requested after terminal_message_emitted=trueNo additional terminal injection message
E5Best-effort cancel still completesCancel requested, tool finishes anywayFinal status allowed as completed
E6Cancel/complete raceCancel arrives after execution already finishedFinal status is completed
E7Idle completion wake-upThread idle when terminal observedRuntime requests next turn boundary, then injects message
E8Cross-thread list/cancel isolationSame job_id queried from non-origin threadNot visible/cancel denied by thread scope
E9Inspect outside threadInspect from wrong threadCanonical not-found-in-thread error
E10Payload exactly-over-limit formattingPayload near policy thresholdsCorrect branch selected (inline vs file), no malformed message
E11Manual retry requestRetryJobRequested invokedCanonical "manual retry not supported" error
E12Process restartJobs exist, process restartsRegistry reinitialized; prior jobs not recovered
E13Internal retryable LLM HTTP errorRetryable HTTP error while job runningNo terminal injection queued; external job status unchanged

Boundary Tests

IDScenarioArrangeAssert
B1Sync/async boundaryTool finishes at threshold between inline and background pathExactly one mode chosen; never both result and job start
B2Global uniqueness at scaleHigh-volume concurrent job creationNo duplicate job_id across runtime
B3Same timestamp ordering tieMultiple completions with equal/near-equal timestampsDeterministic completion-order tie handling (stable ordering policy)
B4At-most-once under concurrent emittersConcurrent emit attempts for same terminal jobExactly one synthetic assistant message persisted
B5Payload size boundariesPayload at max_bytes, max_lines, and +1At-limit stays inline; over-limit spills to temp file
B6Retention at limitExactly 20 terminal jobs in threadNo eviction
B7Retention overflow21+ terminal jobsOldest terminal evicted by completion time; newest kept
B8Mixed retention setTerminal overflow with active non-terminal jobs presentNon-terminal jobs preserved; only terminal jobs evicted

Suggested Test Placement

  • Unit:
    • components/agent-session/test/...background_jobs*_test.clj
    • components/agent-session/test/...job_injection*_test.clj
  • Integration:
    • agent-session runtime + tool dispatcher integration tests
    • synthetic assistant message append/turn-trigger pipeline tests
  • E2E:
    • REPL/TUI/Emacs/RPC parity tests for list/inspect/cancel and terminal injection visibility

Pass Criteria

  • All N/E/B IDs implemented and green.
  • No duplicate terminal injections under concurrency.
  • Ordering and retention behavior deterministic.
  • Cross-thread isolation preserved for list/inspect/cancel.
  • Oversize payload path is observable and debuggable (temp file reference).

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close