mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-14 06:16:20 -06:00
5 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5fa6b2d07d |
A baseline moves when the fix reaches SCREENS, which is not one rule
Two changes that are really one idea: the parity model treated all four
players as if they update the same way, and they do not.
WEB AND BRIGHTSIGN GET audio.volume BACK.
The audit removed it because v1.9.28's index.html contained the string
set_volume zero times, and because the handler read payload.value while the
dashboard sends { level }. The second reason 1.9.31 fixed. The first was
reasoning from the wrong artifact: this player is SERVED BY THE SERVER, so a
browser panel runs whatever build is answering it, not the release its row was
created under. There is no browser panel stuck on the v1.9.28 player once the
server moves — and prod moved tonight. The slider works on those displays right
now while the baseline says it does not, so the dashboard is hiding a working
control from every display that declares nothing.
BrightSign comes with it, on the same served player. The unit-specific doubt is
whether a hwz player's media element is reachable at all — and that is already
answered by audio.mute, which this baseline has always claimed: set_volume
reaches setMediaVolume() and device:mute-changed reaches currentVideoEl.muted,
same element, same path. If hwz swallowed one it would swallow both.
TIZEN DOES NOT COME WITH THEM, AND THE TEST NOW KNOWS WHY.
A .wgt sits on the panel until somebody updates it. Cutting 1.9.31 put nothing
on any screen, so an un-updated Tizen panel still has the broken handler and
moving its baseline would resurrect the dead slider on real hardware.
The test could not express that. It judged every family against "shipped
source", resolved as the newest tag — which is HEAD on a release commit, so
tagging 1.9.31 flipped all four biconditionals at once and demanded a baseline
change for displays that cannot have the fix yet. Green tree, red build, naming
a baseline, with nothing in the diff to explain it. main would have gone red on
the next commit whatever it contained; #242 just got there first.
So the two families are now modelled separately. Server-served: judged against
the working tree, both directions, because both are decidable from the build we
are about to serve. Device artifact: judged against the previous release, and
only in the over-claim direction — "the baseline claims it, so the shipped
player had better implement it" is always true and worth failing on, while
"HEAD gained the handler, so add it" is a guess about how many panels have
updated. The cost is that a stale entry can outlive the artifact reaching the
fleet; that is a judgement about screens, so a person makes it in
player-capabilities.js and records why.
player-capabilities.test.js carried the same stale reasoning hardcoded, and
docs/player-parity.md stated the old facts in four places — a parity matrix
that lies being the exact failure this whole model exists to stop.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014skWYXJUWhF73EvNPgB2AS
|
||
|
|
c1270599c3 |
Make the parity matrix true, and stop three controls that do nothing
The parity doc and the capability model had drifted from the players in both
directions, and nothing failed when they did. Auditing all four players against
their shipped sources turned up three controls a customer can press today that
change nothing, and a set of baselines that were partly too generous and partly
too stingy.
The three dead controls:
- The volume slider works on Android only. The dashboard sends set_volume as
{ level: 0..1 }; the web player reads payload.value and Tizen reads
payload.value ?? payload.volume, so on both the number is undefined and the
handler quietly declines. Three complete, working volume implementations
that cannot be driven. The fix is one line in each player and belongs to
those files; audio.volume is out of the web and brightsign baselines until
it lands, held there by a biconditional test that fails the moment a player
starts reading `level`.
- Every #161 Tier-2 command was refused for the entire fleet. lock_now,
power_menu, status_bar, block_uninstall and unblock_uninstall were gated on
system.device_owner, which no player declares and no baseline grants, so
supports() was false everywhere -- including on the device-owner panels the
feature was built for. The dashboard still drew the buttons because it also
gates on device.tier === 2. Fixed here: those five now accept
system.device_owner OR system.kiosk, which PlayerCapabilities.kt declares
under `if (isOwner)` and nothing else, and which no non-Android player
declares. Android should declare system.device_owner and retire the
stand-in.
- enable_system_capture required the capability it creates. It raises the
MediaProjection consent dialog -- the way a panel GAINS capture -- and was
gated on remote.screenshot, so the only panel that needs it was the one
panel that could not be sent it. Now ungated. The dashboard still hides the
button behind the same check; that half is a frontend change.
The baselines describe what an un-updated fielded display can do, and since
v1.9.29 is the first build in which any player declares anything, that means
v1.9.28. Every entry is now justified against `git show v1.9.28:<source>`:
- android loses display.power (v1.9.28 answers screen_on with a logged no-op,
so the ON half is dead on every fielded panel and one capability renders
both buttons) and system.reboot (owner-only; off-owner it paints an
accessibility power dialog over the signage). Scheduled reboots now skip
undeclared Android panels rather than logging a reboot that never happened,
which is the reason that gate exists.
- tizen gains display.power: v1.9.28 implements both halves with no signing
and no panel API, so withholding it hid a working control.
- brightsign loses audio.volume, display.power, system.reboot,
system.restart_player and offline.cache. All need a host bridge the unit is
not known to have, and restart_player without one is the page reload that
darkened a panel on 2026-07-28.
Also found, not fixed here because the files belong to others:
st-bridge.js computeCapabilities() is dead code -- nothing calls BS.capabilities()
-- and its 199 lines of passing tests constrain nothing a BrightSign actually
declares; the two disagree on six capabilities and the bridge is right about
most of them. BrightSign's "Force update" button is dead. PlayerCapabilities.kt
under-declares display.brightness.
The new test reads the player sources rather than the table: a dead-button rule
(every gated command has a branch somewhere), an unreachable-capability rule
(which would have caught system.device_owner), and biconditionals so a fix in a
player fails the test until the baseline follows. Claims that need hardware --
CEC reaching a display, a widget being allowed a service worker, SyncManager
holding frame lock -- are marked unverifiable in the document instead of
asserted.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
|
||
|
|
e5583e529e |
The Tizen baseline describes a fielded panel, not the one we are shipping
Two more corrections from the cross-player audit, both mine. audio.volume removed: a fielded Tizen panel has NO set_volume handler — the command falls through to "unknown command" and the dashboard slider does nothing. One of the platform branches adds a handler, and those panels will declare the capability for themselves once they run it; the baseline exists to describe an un-updated display, so it must not borrow credit from a build that has not shipped. remote.screenshot and remote.stream added: both really are implemented in the shipped player (captureAndSend, startStreaming). Omitting them would have hidden working controls on every legacy Tizen display the moment gating went live — the opposite failure, and the more damaging one. That asymmetry is the thing to hold on to: over-claiming shows a dead button, under-claiming removes a working one, and only reading the shipped code tells you which you are doing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL |
||
|
|
a08e6c3e06 |
Tizen does not have offline caching — correct the baseline
The platform audit caught my own contract lying. I gave the Tizen baseline offline.cache; Tizen caches only the playlist JSON (st_payload_cache, in localStorage) and has no service worker and no media cache, so the bytes still come from the network and an outage leaves a panel holding a playlist it cannot play. That is exactly the claim this model exists to prevent, made by the model itself, and it would have applied to every legacy Tizen panel — the ones that declare nothing and depend entirely on the baseline being honest. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL |
||
|
|
6bc709d2f7 |
The capability contract: what each player can actually do
Foundation for platform-native parity. The dashboard offered every control to every display — a browser tab cannot reboot its host, a Tizen TV has no device-owner concept, a BrightSign has no per-window brightness — so those buttons did nothing, silently, and read as bugs. "UI that reports success and changes nothing" is a recurring shape here; this ends it by letting the frontend hide what a display cannot do. The player DECLARES its capabilities at registration rather than the server inferring them from a table, because only the player knows at runtime: an Android device gains real screenshots when accessibility is switched on and loses Tier-2 commands when it is not device owner. The trap this had to avoid is the opposite failure. Several hundred displays are in the field declaring nothing, and none will update before the next dashboard deploy — treating absence as "supports nothing" would strip the UI for the entire fleet at once. So an ABSENT declaration falls back to a per-platform baseline, while an EMPTY one is honoured as a player genuinely saying it can do nothing. Those two cases are trivial to conflate and the difference is a dark dashboard. Baselines carry only what has always worked on that platform. Anything conditional — screenshots needing accessibility, kiosk needing device owner, native sync needing one L2 network — is omitted, so a legacy display shows those controls only once it declares them. A control that appears late beats one that lies now. Capability names are stable strings because they are persisted per device and sent over the wire; renaming one silently disables a control on every display still reporting the old name. An unknown name from a NEWER player is dropped rather than invalidating the whole declaration. 1094 pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL |