# Observed frame contract

This document records the frame format confirmed by Qlyra's web push protocol
implementation and the native client contract used by Qlyra. Live service
compatibility still requires account-level verification.

## Header

Each frame starts with ten bytes in network byte order.

| Bytes | Field | Encoding |
| --- | --- | --- |
| 0 | protocol version | unsigned 8-bit integer |
| 1 | command | unsigned 8-bit integer |
| 2-3 | sequence | signed 16-bit integer on the Dart web path; the wire bytes are preserved by `kusoft-net` |
| 4-5 | opcode | signed 16-bit integer on the Dart web path; the wire bytes are preserved by `kusoft-net` |
| 6 | compression marker | unsigned 8-bit integer |
| 7-9 | payload length | unsigned 24-bit integer |

The payload follows immediately after the header. The maximum encodable length
is `0x00ffffff` bytes.

## Confirmed values

The local web implementation writes protocol version `10`. It uses command
values `0` (request), `1` (ok), `2` (not found), and `3` (error). It serializes
uncompressed payloads with MessagePack.

## Compression boundary

The web implementation treats a non-zero compression marker as LZ4 block data.
The native decoder accepts bounded LZ4 block, LZ4 frame, and Zstd payloads.
Decompressed output is limited to 32 MiB.

## Synthetic conformance vector

`0a 00 00 02 00 06 00 00 00 03 aa bb cc`

This vector represents version `10`, command `0`, sequence `2`, opcode `6`, no
compression, and the three-byte payload `aa bb cc`. It contains no account,
device, message, or server data.

## Sources in this repository

- `lib/core/webpush/max_web_protocol.dart`, lines 21-85
- `lib/core/protocol/packet.dart`, lines 3-38
- `lib/core/protocol/opcode_map.dart`, lines 9-26
- `test/max_web_protocol_test.dart`, synthetic fixtures
- `third_party/kusoft-net/src/session.rs`, synthetic TLS session integration test
- `third_party/kusoft-net/src/media.rs`, synthetic HTTP upload integration test
- `third_party/kusoft-net/src/calls.rs`, synthetic ws2 integration test
