feat(protocol): make image transfers canonical and stateful #81
No reviewers
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis!81
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/image-transfer-state-machine-51"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #51.
The image wire carried two encodings of the root frame with different meanings —
frame: Nonereplaced the image and dropped its animation frames,frame: Some(0)edited the root's pixels in place — and both were reachable from real Kitty traffic (a=tversusa=f, r=1). A frame header also repeated width/height/format the receiver ignored, chunks claimed a random access nothing verified, andCompletemarked a buffer renderable whatever had arrived, painting a dropped chunk as transparent pixels the producer never sent.What changed
New { width, height, format }starts a fresh image,Frame { number }addresses one frame in Kitty's own 1-based numbering (ShowFramecounts the same way), so the two meanings have two shapes and frame0is not expressible.total_bytesand a chunk'soffsetare gone: every buffer of an image iswidth × height × bytes_per_pixel, and the receiver runs one transfer at a time, appending chunks at its own byte count.ImageShadow::applyreturns a typed error for every sequence the machine has no transition for, which the window turns into the same connection-local teardown a refused claim already got.ImageHeader.frame) is acknowledged incrates/felis-protocol/proto/BREAKING.md; it rides the current pre-release major.Doc cascade
docs/reference/ipc.mdanddocs/reference/protocols/kitty-graphics.mdrecord the resulting facts (one target per meaning, ordered chunks, one transfer at a time, the malformed list);docs/explanation/architecture/ipc.mdanddocs/explanation/protocols/kitty-graphics.mdown the argument, including the two rejected shapes — offset-addressed chunks and a 0-based optional frame index — and what would make either worth revisiting.docs/explanation/data-model/image-store.md,docs/reference/testing.md, andCHANGELOG.mdfollow.Verified: just check green (fmt, clippy, nextest, deny); reviewed by plan/correctness/docs lenses and pi sol
Deferred
materialize_image_eventsthat no Header is queued while a prior transfer's Complete is pending — the plan calls it a cheap future-proofing catch, but no acceptance criterion asks for a producer-side guard and the receiver already refuses the sequence.ImageShadowError::DimensionsOverCapas a distinct variant — #49 landed already; its caps surface as the existingImageBytes/SessionBytes/FrameIndexvariants, so this would be a rename with no new behavior.felis-daemonintegration test shipping a two-frame image through the codec onto a liveImageShadow— the existingimage_outbox_materialization.rssuite already round-trips producer output through the shadow and passes unchanged; a second end-to-end fixture would duplicate it without covering a criterion the shadow unit tests miss.docs/explanation/architecture/ipc.md's older "let the client trust the daemon" paragraph beyond the one sentence that named chunk offsets — its argument is untouched by this change; a fuller rewrite is prose work no criterion needs.The image wire carried two encodings of the root frame with different meanings — `frame: None` replaced the image and dropped its animation frames, `frame: Some(0)` edited the root's pixels in place — and both were reachable from real Kitty traffic (`a=t` versus `a=f, r=1`). A frame header also repeated width/height/format the receiver ignored, chunks claimed a random access nothing verified, and `Complete` marked a buffer renderable whatever had arrived, painting a dropped chunk as transparent pixels the producer never sent. The header now names one target: `New { width, height, format }` starts a fresh image, `Frame { number }` addresses one frame in Kitty's own 1-based numbering (`ShowFrame` counts the same way), so the two meanings have two shapes and frame `0` is not expressible. `total_bytes` and a chunk's `offset` are gone: every buffer of an image is `width × height × bytes_per_pixel`, and the receiver runs one transfer at a time, appending chunks at its own byte count. `ImageShadow::apply` returns a typed error for every sequence the machine has no transition for, which the window turns into the same connection-local teardown a refused claim already got. Refs #51