T1.7: Move QualityReport trailer inside AEAD payload
This commit is contained in:
65
docs/PRD/reports/T1.7-report.md
Normal file
65
docs/PRD/reports/T1.7-report.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# T1.7 — Move `QualityReport` trailer inside AEAD payload
|
||||
|
||||
**Status:** Pending Review
|
||||
**Agent:** Kimi Code CLI
|
||||
**Started:** 2026-05-11T11:05Z
|
||||
**Completed:** 2026-05-11T16:29Z
|
||||
**Commit:** c9fa10d
|
||||
**PRD:** ../PRD-protocol-hardening.md
|
||||
|
||||
## What I changed
|
||||
|
||||
- `crates/wzp-client/src/call.rs:1613` — Added `quality_report_aead_tamper_fails_decrypt` test confirming that when a `MediaPacket` with `quality_report` is serialized and then encrypted with `ChaChaSession` (header as AAD, payload+QR as plaintext), tampering with any byte in the QR region causes AEAD decryption to fail.
|
||||
|
||||
## Why these choices
|
||||
|
||||
The `MediaPacket::to_bytes()` serialization already places the `QualityReport` trailer immediately after the payload in the same contiguous buffer. The `ChaChaSession::encrypt` API already accepts `header_bytes` as AAD and `plaintext` as the message to seal. Therefore the existing architecture naturally supports the desired ordering:
|
||||
|
||||
1. `MediaHeader` → serialized as AAD
|
||||
2. `payload || QualityReport` → serialized as plaintext
|
||||
3. AEAD-seal over (plaintext, AAD)
|
||||
|
||||
No production code changes were required because there is no live media encryption path in `cli.rs` today (`_crypto_session` is derived but discarded). The task’s goal was to verify the API boundary and add a regression test so that when a future task wires encryption into the send loop, the QR will automatically sit inside the AEAD payload.
|
||||
|
||||
## Deviations from the task spec
|
||||
|
||||
None. Followed steps T1.7.1 through T1.7.5 without deviation. Step 3 (“If currently appended after AEAD seal: refactor”) was a no-op because no production path appends the QR after encryption.
|
||||
|
||||
## Verification output
|
||||
|
||||
```bash
|
||||
$ cargo test -p wzp-client quality_report_aead
|
||||
running 1 test
|
||||
test call::tests::quality_report_aead_tamper_fails_decrypt ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 169 filtered out; finished in 0.00s
|
||||
```
|
||||
|
||||
```bash
|
||||
$ cargo test -p wzp-crypto
|
||||
running 36 tests
|
||||
...(all 36 pass)...
|
||||
|
||||
test result: ok. 36 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s
|
||||
```
|
||||
|
||||
## Test summary
|
||||
|
||||
- Tests added: 1 (`quality_report_aead_tamper_fails_decrypt`)
|
||||
- Tests modified: 0
|
||||
- Workspace test count before: 571 / after: 572 (1 added in `wzp-client`)
|
||||
- `cargo clippy --workspace --all-targets -- -D warnings`: pass in crates touched (`wzp-client`, `wzp-crypto`); 12 known-debt errors in `wzp-codec` + `warzone-protocol` (see PROTOCOL-AUDIT.md)
|
||||
- `cargo fmt --all -- --check`: pass
|
||||
|
||||
## Risks / follow-ups
|
||||
|
||||
- No production media encryption path exists yet. When one is added (likely in a future wave), the send loop must pass `pkt.to_bytes()[MediaHeader::WIRE_SIZE..]` as the plaintext to `CryptoSession::encrypt` and `pkt.header.to_bytes()` as AAD. The `analyzer.rs` replay decrypt path already follows this pattern.
|
||||
- Mini-frame compression (`encode_compact`) does not carry `quality_report` by design (mini frames are payload-only deltas). This is acceptable because quality reports are sent on full frames, which the encoder already does.
|
||||
|
||||
## Reviewer checklist (filled in by reviewer)
|
||||
|
||||
- [ ] Code matches PRD intent
|
||||
- [ ] Verification output is real (re-run if suspicious)
|
||||
- [ ] No backward-incompat surprises
|
||||
- [ ] Tests cover the new behavior
|
||||
- [ ] Approved
|
||||
Reference in New Issue
Block a user