Commit Graph

6 Commits

Author SHA1 Message Date
Tianyi Cui
0af16387ae fix(telemetry): rename record waterfall 2026-07-27 21:30:28 +08:00
kingwl
bf76c52d76 fix(telemetry): reject non-positive maxExportBatchSize at plugin load
Review finding, pinned red-first: the SDK accepts
processor.maxExportBatchSize <= 0 (or fractional), but its shutdown
drain then splices empty batches without consuming the queue —
disposing telemetry hangs forever whenever records are queued. The
constructor now rejects a non-positive-integer batch size before
building the SDK processor, per the misconfiguration-fails-loud rule;
everything else in the processor block remains the SDK's verbatim
passthrough.
2026-07-27 20:11:30 +08:00
kingwl
a72436105b docs(telemetry): state the crash-repair export semantics for resumed streams
Review finding: synthetic turn closers written by SessionPersistence
.load() at crash-resume sit below firstLiveSeq and are never exported,
leaving the remote turn unbalanced. Kept deliberately — exporting a
synthetic closer cannot complete a turn whose real tail records died
in the crashed process's queue; it can only make an incomplete turn
look closed. The OTel README now states the receiver rule (a
never-closed turn on a resumed stream marks the previous process dying
inside it; a later clean shutdown marker attests only to the resumed
process's exit), and the revival Agent Note records why the repair
suffix stays local.
2026-07-27 19:49:19 +08:00
kingwl
6adb14b56d feat(telemetry): adopt from the construction boundary — constructor seeds never re-export
A cursor-less adoption (process restart + resume, fork, seam-module
reload) replayed the session's full log from seq 0, re-exporting
history that already left the process — a resume re-billed its entire
stored log on every restart, and a fork re-shipped the parent's prefix
under the child's id, doubling query-time counts on OTLP backends with
no native ingest dedupe.

dsh-session now exposes the fact the constructor already validated but
discarded: Session.firstLiveSeq, the constructor-seed length — the
first seq appended in this process. header.seedLength cannot serve
here: it is the durable fork-lineage boundary, and a resumed session's
constructor seed is its full stored log while the header keeps the
original fork value (llm-replay and session-query-sqlite depend on
that meaning). Constructor seeds also never publish on the
session/event firehose, so adoption replaying them was inconsistent
with the system's own publication semantics.

Adoption's cursor-less fallback starts at firstLiveSeq; seed events
still feed the chunk projection, so mid-step continuations re-drop
after a resume. Fork streams are no longer self-contained: records now
carry session.seed_length (with the existing session.parent_id) so
receivers stitch the child's stream onto the parent's. Accepted cost,
consistent with at-most-once delivery and recorded in the revival
Agent Note: a resume no longer backfills records a previous process
failed to deliver — a deployment with that requirement needs the
deferred outbox, not replay.

Pinned red-first: seeded adoption exports nothing (assertion reversed
from the prior seed-readback test, obsolete behavior changed with its
test), resume-shaped seed rebuilds the projection without exporting,
and fork records carry the stitch attributes.
2026-07-27 18:35:03 +08:00
kingwl
95315386b3 refactor(telemetry): remove the OTel backend's flush forwarding
Three review rounds each found a new silent-loss path in the same
wrapper state (dispose racing an in-flight flush, overlapping hints
displacing the retained promise, the provider's fixed 30s flush timeout
rejecting while the processor still drains). Every path exists only
because forwarding the seam's turn-boundary hint to forceFlush() made
this backend the process's second flusher against undocumented SDK
internals from the upstream experimental tree.

The backend now implements no flush(): the batch processor is the only
flusher, its scheduledDelayMillis (already deployment-tunable through
the processor passthrough) governs export cadence, and shutdown()'s
drain is complete by construction. The two race-pin tests collapse into
one dispose-during-in-flight-batch drain pin; the seam's optional
flush() contract now tells implementers they own the concurrent-flush/
shutdown interaction. Removal rationale and the reinstatement trigger
(a stated turn-boundary latency requirement scheduledDelayMillis cannot
meet — and then via the processor's own forceFlush(), never the
provider's timeout-wrapped one) are recorded in the revival Agent Note,
both languages.
2026-07-26 17:55:54 +08:00
kingwl
e8d8589219 Merge remote-tracking branch 'origin/master' into feat/telemetry-otel-plugin
Resolutions: regenerate docs/capability-seams.md (the only conflict);
master widened the bilingual pairing scope to package READMEs, so this
merge adds the Chinese counterparts and i18n records for the three
telemetry READMEs and patches packages/README.zh.md with the telemetry
group row.
2026-07-26 16:58:35 +08:00