# Schema 3.3.0

ClientIssue.key, generator rewrite, and a protobuf renumbering warning

Version coverage: /docs/reference/versions/


{{< callout context="caution" title="Wire-format warning" icon="alert-triangle" >}}
`ClientIssue` field numbers shift, because protobuf numbering follows sorted field order and `key`
sorts before `payload`:

| Field | 3.2.0 number | 3.3.0 number |
|---|---|---|
| `type` | 1 | 1 |
| `key` | — | 2 |
| `payload` | 2 | **3** |
| `timestamp` | 3 | **4** |

**A decoder built against 3.2.0 will misread these.** Upgrade both halves of your codec together —
and note that `@observertc/samples-encoder` / `@observertc/samples-decoder` were deprecated in
[3.4.0](../v3-4-0/) in favour of [`samples-protobuf-codec`](/docs/codecs/protobuf/).
{{< /callout >}}

## Added

### ClientIssue.key

```jsonc
{
  "name": "key",
  "doc": "Identifier of the related issue or resolution when it is provided.",
  "type": ["null", "string"],
  "default": null
}
```

This one field is what turns a stream of point-in-time symptom reports into **intervals**.

`client-monitor-js` ≥ 4.6.0 sends a stateful issue as two entries sharing a `key`:

```text
raise:       { type: 'stuck-decoder',          key: 'stuck-decoder-track-7', payload, timestamp: raisedAt  }
resolution:  { type: 'stuck-decoder-resolved', key: 'stuck-decoder-track-7', payload, timestamp: resolvedAt }
```

`observer-js` pairs them, strips the `-resolved` suffix, and emits `client-issue-resolved` carrying
`durationInMs` and `resolvedBy`. Without the key there is nothing to pair on, and every
cross-participant detector has to guess whether a reported symptom is still happening.

See [Detectors — the wire format](/docs/client-monitor-js/events-and-issues/).

### IceCandidatePairStats.state documentation

The field gained documentation recording which `RTCStatsIceCandidatePairState` symbols are no
longer in the W3C spec:

- **`new`** — never standardised. An ObserveRTC-only value, retained for backward compatibility.
- **`cancelled`** — removed after
  [w3c/webrtc-stats#66](https://github.com/w3c/webrtc-stats/issues/66) established that RFC 5245
  §5.7.4 defines no such state. Last published in the 2016-12-14 Working Draft.

Both symbols are **retained**. No field or enum value was removed, so the wire format is unchanged
by this.

Current spec values: `frozen`, `waiting`, `in-progress`, `failed`, `succeeded`.

{{< callout context="note" title="Why `inProgress` in the Avro source" icon="info-circle" >}}
Avro enum symbols must match `[A-Za-z_][A-Za-z0-9_]*`, so the spec's hyphenated `in-progress`
cannot be spelled directly. The source uses `inProgress` and the generator rewrites it back to
`in-progress` when emitting the TypeScript union (also accepting the legacy one-word
`inprogress`).
{{< /callout >}}

## Changed

### The generator was rewritten in TypeScript

The legacy `index.js` and its root-level helpers were removed; the generator now lives in `src/`
and runs with `npm run generate`. **Generated TypeScript, Avro and protobuf output is
byte-identical** to the previous implementation.

New CLI shortcuts:

```bash
npm run generate            # everything
npm run generate:check      # fail if committed outputs are stale (CI)
npm run generate:dry-run    # show what would change, write nothing
npm run generate:types      # TypeScript and Avro only
npm run generate:proto      # protobuf only
npm run generate:docs       # Markdown reference + schema library README
npm run schemas:list        # list discovered schemas and chunks
npm run schemas:validate    # validate and check every field is documented
```

### schemaVersion export

Now exported from the `ClientSample` module only. It was previously emitted by every generated
module, which made `src/index.ts` re-export the same name twice and broke `npm-samples-lib`'s build
(TS2308). The package still exports `schemaVersion` from its entry point.

### Generated Markdown

- No longer runs a section heading onto the end of the preceding table row.
- No longer prints `undefined` for enum fields with no description.

### Toolchain

- All packages moved to TypeScript 7 with `"module": "nodenext"`. Emit is still `CommonJS`; published
  entry points are unchanged.
- Dependencies refreshed: `avro-js` 1.12.1, `@bufbuild/buf` 1.72.0, `@bufbuild/protobuf` and
  `@bufbuild/protoc-gen-es` 2.13.0.
- Removed `argparse`, `json-schema-to-markdown`, `protobufjs` and `typedoc` — none were used.

## Fixed

### @observertc/samples-decoder could not be imported

`ClientSampleDecoder` imported `fromBinary` from `@bufbuild/protobuf/dist/cjs/from-binary`, a path
that stopped existing in protobuf-es v2. Requiring the package threw
`ERR_PACKAGE_PATH_NOT_EXPORTED`. It now imports from the package root.

{{< callout context="tip" title="If you were pinned below 3.3.0 because of this" icon="rocket" >}}
This was a hard blocker for anyone using the binary transport path — the decoder simply would not
load. Upgrading to 3.3.0 fixes it, and the encoder must move with it.
{{< /callout >}}

## Upgrade checklist

{{< steps >}}
{{< step >}}Upgrade `@observertc/samples-encoder` and `@observertc/samples-decoder` **together** to 3.3.0.{{< /step >}}
{{< step >}}Re-encode or decode-with-the-matching-version any stored binary samples written by 3.2.0 that contain `clientIssues`.{{< /step >}}
{{< step >}}Upgrade `client-monitor-js` to ≥ 4.6.0 if you want keyed issue raise/resolve pairs to reach the server.{{< /step >}}
{{< step >}}Register issue-driven detectors in `observer-js` — they depend on the keyed format.{{< /step >}}
{{< /steps >}}

[← Back to version history](/docs/schema/versions/) · [3.2.0 →](../v3-2-0/)

