Skip to content

cendor-sdk 1.19.1

Choose a tag to compare

@github-actions github-actions released this 25 Jul 23:35

Two concurrent runs no longer cross-contaminate the automatic scope. Found by review after the
zero-telemetry-code wave and reproduced with a client that has real latency — every acceptance probe
had been sequential, and an instant stub finishes one run before the next starts, so the bus never
interleaved.

Fixed

  • Cross-run adoption. A live_spans scope learned its run family from the first bus event it saw,
    and bus.emit is a process-wide fanout — so two overlapping runs rendered one run's call twice
    (once under each root), dropped the other run's call entirely, and stamped both roots with the
    same cendor.run.id. In a backend that sums gen_ai.usage.cost over spans that is double-counted
    spend plus a lost run. A run family now has exactly one owning scope, and the automatic scope
    learns only from an event emitted inside its own context (a user's explicit
    with live_spans(...) keeps the historical "first event wins" — it may legitimately wrap work that
    runs on another thread, where no context reaches).
  • A run-less call is no longer adopted into a run. An LLMCall/ToolCall carrying no run id
    belongs to no run: core's flat emitter renders it, the run scope must not (it used to become the
    run's step 1, putting a foreign call's cost inside the run). Falls back to the ambient
    trace() scope first, exactly like the domain-span path.

Added (tests only)

  • Governance precedence pinned under concurrency — the wave only probed it sequentially. Two
    overlapping runs with one AuditLog between them: both decisions ride the chain as
    audit.budget_event (an AuditLog auto-populates from the whole process bus) and core's Option C
    spans stand down for both; with no AuditLog, each run gets exactly one governance.budget_event.
    Never twice, never zero.

Unchanged

  • The public API, the run ids, the spans and their attributes. Python's latch was never affected by
    the Node-LTS enterWith defect, and the streaming paths were already context-scoped
    (_drive_sync's copied context / _drive_async's producer task) — this release brings the TS port
    in line with them; see @cendor/sdk 0.23.2.