Review follow-up: the llm/adapters-updated listener's disposer was
discarded, leaving it firing (harmlessly, behind isDisposed()) between
TUI shutdown and fiber disposal, asymmetric with the sibling channel
listeners. The controller now exposes detach(), and the channel's
detachListeners() calls it on both the dispose() and startup-failure
paths.
Loader activation is service-driven, so the TUI can mount before a
configured adapter plugin registers its provider routes; every fresh
session then printed 'Could not resolve model context: no adapter
registered for provider …' for a working configuration.
The model controller now treats a NO_ADAPTER rejection of the
context-window resolution as transient: it parks the resolution
silently and re-resolves on the next llm/adapters-updated commit. A
commit that still lacks the route parks the wait again; any target
change clears it; all other resolution errors still surface. A wrong
provider name keeps failing loudly at dispatch, where it is actionable.
- Split DSH_COVERAGE_MAX_WORKERS between the two parallel gates
(instrumented gets ~2/3, exempt gets ~1/3, both at least 1) so the
lane never exceeds the budget the failover pool's 8 x 6-instance
bound assumes; a budget of 1 pairs with DSH_GATE_CONCURRENCY=1 on
the serial reference lanes, which already prevents gate overlap.
- Fail loud on a set-but-not-'1' DSH_COVERAGE_EXEMPT_HEAVY value in
vitest.config.ts instead of silently ignoring it.
- Add coverage-exempt.spec.ts: each roster entry's filter and exclude
must select the same non-empty spec set and entries must not
overlap, so a renamed suite breaks the gate instead of silently
returning to the instrumented run with a stale roster.
Agent Note (both languages, pairing recorded): what is exempted, the
per-entry reconciliation showing no threshold input changes, the
membership contract, and why the per-file 100% thresholds police the
roster automatically.
The coverage lane's wall clock was pinned by a few compiler- and
subprocess-bound suites whose v8 instrumentation tax is a multiple of
their runtime while contributing nothing the per-file thresholds need:
typert generator fixtures (whole-workspace compiler analysis; its src is
threshold-excluded) and three scripts/ child-process fixture suites
(scripts/ sources are never coverage-measured; in-process imports are
covered by their owning package tests).
Split ci-coverage into two parallel gates: the instrumented run sets
DSH_COVERAGE_EXEMPT_HEAVY=1 and vitest.config.ts drops the exempt suites
from both projects (CLI --exclude cannot reach per-project include
resolution); a second uninstrumented gate runs exactly those suites, so
the aggregate still executes every test. Membership contract and the
filter/exclude pairs live in scripts/coverage-exempt.ts.
Local 6-worker A/B: instrumented gate 900s -> 260s wall; exempt gate
262s wall runs beside it, so the lane converges near the slower of the
two (~4.4min vs ~7min single-gate). DSH_GATE_CONCURRENCY now has two
schedulable gates in this lane.
The row moves from web.cordis.yml to base.cordis.yml, so the TUI reports
too (its exit paths already drain: disposeRootAndExit on normal exit, root
dispose before the /resume execve). The TUI launcher applies the same
resolveTelemetryPatch opt-out, judged against the tree actually booting via
configHasTelemetryRow so a --config-replace tree without the row is not
failed by a switch with nothing to disable. The TUI keyless smoke disables
telemetry in its child env; README (en/zh) and the Agent Note pair updated
to the every-surface stance.
The pairing gate requires both sides of a bilingual pair to link the same
target; point the zh side's cross-references at the English canonical files
and re-record both i18n pairings.
- resolveTelemetryPatch: extracted pure switch resolution (unit-tested);
fails loud when DSH_TELEMETRY_DISABLED is set but the row is absent, and
documents that ANY non-empty value (including '0'/'false') disables.
- runHeadless: SIGINT/SIGTERM now dispose the tree before exit so the
telemetry tail and shutdown marker drain (Node's default signal exit
skips disposal).
- web.cordis.yml: explicit maxQueueSize beside maxExportBatchSize (the
single-batch drain invariant no longer leans on an SDK default), comment
covers exportTimeoutMillis's role and links the Agent Note.
- apps/web scaffold: disable telemetry-otel — fixture sessions must never
leave the process.
- apps/cli README (en/zh + pairing): document the default endpoint, both
env seams, and the no-redaction disclosure.
Pins the deployment rulings: default-on with the production endpoint,
DSH_TELEMETRY_OTLP_URL / DSH_TELEMETRY_DISABLED env seams, 10s cadence,
the ~1s exit-drain parameter set, CI isolation, and the explicit
follow-ups (redaction, identity resource, TUI adoption, metrics).
apps/cli/cordis.yml now bakes in the production OTLP endpoint; CI boots of
the web composition (e2e, snapshots, built smokes) must not stream test
sessions there. DSH_TELEMETRY_DISABLED=1 at the workflow level disables
the telemetry row before its load-time url validation; the telemetry e2e
still runs — it overrides the variable to empty for its child process and
points DSH_TELEMETRY_OTLP_URL at its in-test collector.
Boot the real dsh web tree against an in-test OTLP/HTTP collector and a
mock LLM server, drive one turn over /api, then SIGINT. Asserts the wire:
OTLP JSON structure and resource identity, both instrumentation scopes,
ledger event coverage in seq order, prompt fidelity in the exported body,
the first-of-step chunk projection, and the ops shutdown marker arriving
through the exit drain.
Mount the existing telemetry seam + OTel logs backend in the web/headless
config tree so every session-log event streams to an OTLP/HTTP collector:
- telemetry-otel row: url defaults to the standard local OTLP endpoint,
DSH_TELEMETRY_OTLP_URL overrides; 10s batch cadence; exporter/processor
values bound the shutdown drain to ~1s against an unreachable collector
(timeoutMillis doubles as the retry deadline, single-batch drain).
- DSH_TELEMETRY_DISABLED opt-out: AppCLIEntry patches the row disabled
before boot (config alone cannot disable a row, and exporter.url
validation is load-time fail-loud).
The plan-review golden landed on master (63c477f14) recorded against the
old command-row rendering; this branch drops the slash and the argument
echo, so the approved-state transcript line changes accordingly.
GitHub created no workflow runs and no check runs for eaaec8173, leaving the
two required contexts waiting for a status that was never going to arrive.
Empty commit, identical tree — this only makes GitHub emit the pull_request
event again.