fix: include orientation in device 304 cache check
CI / test (push) Has been cancelled

The 304 short-circuit at DeviceImageController only compared image IDs,
so flipping a device between landscape and portrait would not invalidate
the cache: the device kept showing the previously-rendered .bin even
after the user changed orientation in the webapp.

Now the device row tracks currentImageOrientation — set whenever a 200
binary response is sent — and the 304 path requires both image id AND
current orientation to match the device's stored orientation. An
orientation flip naturally falls through to the 200 path on the next
poll, the freshly-rendered portrait .bin is delivered, and the device
redraws.

No firmware change: the existing X-Current-Image-Id header from the
device is sufficient. Existing devices migrate cleanly — null
currentImageOrientation just forces one full re-send on first post-
migration poll, which is harmless.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-06 14:21:15 -04:00
parent 70d48f9b11
commit c387260ee7
4 changed files with 84 additions and 1 deletions
@@ -167,6 +167,9 @@ class DeviceImageControllerTest extends AppWebTestCase
$imageId = $image->getId();
$device->setLockedImage($image);
// Simulate the device having already received this image at the current
// orientation — the 304 path now requires this to match too.
$device->setCurrentImageOrientation(Orientation::Landscape);
$this->em()->flush();
$this->client->request('GET', '/api/device/' . self::MAC . '/image', [], [], [
@@ -176,6 +179,38 @@ class DeviceImageControllerTest extends AppWebTestCase
$this->assertResponseStatusCodeSame(304);
}
public function test_orientation_flip_returns_200_even_when_image_id_matches(): void
{
$setup = $this->createTestSetup();
$device = $setup['device'];
$image = $setup['image'];
$imageId = $image->getId();
// Seed: device receives the image at landscape orientation.
$this->client->request('GET', '/api/device/' . self::MAC . '/image');
$this->assertResponseStatusCodeSame(200);
// User flips device to portrait and a portrait render is ready.
$this->em()->clear();
$device = $this->em()->find(Device::class, $setup['device']->getId());
$device->setOrientation(Orientation::Portrait);
$portraitAsset = (new RenderedAsset())
->setImage($this->em()->find(Image::class, $imageId))
->setDeviceModel(DeviceModel::V1)
->setOrientation(Orientation::Portrait)
->setStatus(RenderStatus::Ready)
->setFilePath(self::BIN_PATH);
$this->em()->persist($portraitAsset);
$this->em()->flush();
// Same image ID, but device's stored orientation (landscape) no longer
// matches the device's current orientation (portrait) → must re-send.
$this->client->request('GET', '/api/device/' . self::MAC . '/image', [], [], [
'HTTP_X-Current-Image-Id' => (string) $imageId,
]);
$this->assertResponseStatusCodeSame(200);
}
public function test_poll_advances_current_image(): void
{
$setup = $this->createTestSetup();