mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 17:45:53 +01:00
docs(telemetry): document the sandbox duplex transport contract
The duplex transport adds spans, one event, counters, and dimensions in duplex-telemetry.ts. The generated telemetry contract does not cover them, so the telemetry README is their canonical contract. Add a section for the span, event, and counter names, the closed dimension-key set with its enum values, and the opt-in and no-user-content rules. Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 file changed
+62
@@ -304,6 +304,68 @@ record, so a worker can never forge a parent. The host validates the
|
||||
trace context the worker sends no span, so the whole provider-span path is a
|
||||
no-op.
|
||||
|
||||
## Sandbox Duplex Transport Telemetry
|
||||
|
||||
Paperclip opens a fixed observability surface for the sandbox duplex transport.
|
||||
This surface is separate from the first-party events and from the startup spans
|
||||
above. The generated telemetry contract does not cover it, so this section is its
|
||||
canonical contract. The code owner is
|
||||
`packages/adapter-utils/src/duplex-telemetry.ts`. That module holds each name and
|
||||
each enum value as a literal constant, so the surface never drifts.
|
||||
|
||||
The surface is opt-in. The host injects a recorder that binds the span to the
|
||||
OTel tracer, the counter to the guarded counter store, and the event to the
|
||||
run-events bridge. The default recorder is a no-op, so the whole surface stays
|
||||
inert until the host binds a real recorder. Every recorder call sits inside an
|
||||
error swallow, so a telemetry failure never breaks the request path.
|
||||
|
||||
The surface carries no user content. No route, no query, no request body, no
|
||||
token, and no raw identifier rides a span, a counter, or an event. Each record
|
||||
carries only the closed dimension keys below and, for the request span, a
|
||||
latency. The `provider` dimension carries only the allowlisted public value
|
||||
`daytona`. Any other plugin key maps to `other` before the record reaches a sink,
|
||||
so a raw plugin key never reaches a span attribute, a counter label, or an event
|
||||
field.
|
||||
|
||||
### Spans
|
||||
|
||||
| Span | Scope | Latency |
|
||||
| --- | --- | --- |
|
||||
| `sandbox.duplex.channel_open` | One duplex channel-open attempt. The `outcome` dimension is `ok` when the channel opened and readiness passed, or `error` when the open or readiness failed. | none |
|
||||
| `sandbox.duplex.request` | One duplex request the broker forwarded to the host. | The request latency in milliseconds. |
|
||||
|
||||
### Event
|
||||
|
||||
| Event | Scope |
|
||||
| --- | --- |
|
||||
| `sandbox.duplex.transport` | The host emits it at each transport boundary: a ready duplex channel, a fallback to the file bridge, and a terminal channel loss. Its dimensions record the boundary. |
|
||||
|
||||
### Counters
|
||||
|
||||
| Counter | Scope |
|
||||
| --- | --- |
|
||||
| `sandbox_duplex_channel_open_total` | One successful duplex channel open. |
|
||||
| `sandbox_duplex_fallback_total` | One fallback to the file bridge. The `fallback_reason` dimension records the cause. |
|
||||
| `sandbox_duplex_loss_total` | One terminal duplex channel loss. The `loss_class` dimension records the phase. |
|
||||
| `sandbox_duplex_session_leak_total` | One leaked provider session at teardown. |
|
||||
|
||||
### Dimension keys
|
||||
|
||||
Every span attribute, counter label, and event field uses only these closed keys.
|
||||
A test asserts the exact set, so a new key never reaches a sink by accident.
|
||||
|
||||
| Key | Type | Optional | Value set |
|
||||
| --- | --- | --- | --- |
|
||||
| `provider` | string | no | `daytona`, or `other` for any other plugin key. |
|
||||
| `transport` | string | no | `duplex` or `file`. A fallback record uses `file`; every other record uses `duplex`. |
|
||||
| `outcome` | string | yes | `ok` or `error`. |
|
||||
| `fallback_reason` | string | yes | `gate_off`, `capability_absent`, `open_failed`, `ready_invalid`, `ready_nonce_mismatch`, `ready_timeout`, or `contaminated`. It rides only a fallback record. |
|
||||
| `loss_class` | string | yes | `pre_dispatch` or `post_dispatch`, relative to the first request dispatch. It rides only a loss record. |
|
||||
|
||||
To add a name or an enum value, extend the literal constant in
|
||||
`duplex-telemetry.ts` first, then update the test that asserts the closed set.
|
||||
Keep every dimension low-cardinality and free of user content.
|
||||
|
||||
## Sandbox Startup Run-Log Event
|
||||
|
||||
Paperclip writes one `run.startup.step` event to the run log for each bring-up
|
||||
|
||||
Reference in new issue
Block a user