ffmpeg version 7.1.3-0+deb13u1+rpt1 Copyright (c) 2000-2025 the FFmpeg developers
  built with gcc 14 (Debian 14.2.0-19)
  configuration: --prefix=/usr --extra-version=0+deb13u1+rpt1 --toolchain=hardened --incdir=/usr/include/aarch64-linux-gnu --enable-gpl --disable-stripping --disable-libmfx --disable-mmal --disable-omx --enable-gnutls --enable-libaom --enable-libass --enable-libbs2b --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libglslang --enable-libgme --enable-libgsm --enable-libharfbuzz --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-openal --enable-opencl --enable-opengl --disable-sndio --disable-libvpl --libdir=/usr/lib/aarch64-linux-gnu --arch=arm64 --enable-neon --enable-v4l2-request --enable-libudev --enable-epoxy --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-vout-drm --enable-chromaprint --enable-frei0r --enable-ladspa --enable-libbluray --enable-libcaca --enable-libdvdnav --enable-libdvdread --enable-libjack --enable-libpulse --enable-librabbitmq --enable-librist --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libx264 --enable-libzmq --enable-libzvbi --enable-lv2 --enable-sand --enable-sdl2 --enable-libplacebo --enable-librav1e --enable-pocketsphinx --enable-librsvg --enable-libjxl --enable-shared
  libavutil      59. 39.100 / 59. 39.100
  libavcodec     61. 19.101 / 61. 19.101
  libavformat    61.  7.100 / 61.  7.100
  libavdevice    61.  3.100 / 61.  3.100
  libavfilter    10.  4.100 / 10.  4.100
  libswscale      8.  3.100 /  8.  3.100
  libswresample   5.  3.100 /  5.  3.100
  libpostproc    58.  3.100 / 58.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/sebas/outputs/inbox/fullscreen-test/14597490_2160_3840_60fps.mp4':
  Metadata:
    major_brand     : iso5
    minor_version   : 512
    compatible_brands: iso5iso6mp41
    encoder         : Lavf60.16.100
  Duration: 00:00:14.40, start: 0.000000, bitrate: 17734 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 2160x3840, 17730 kb/s, 60 fps, 60 tbr, 15360 tbn (default)
      Metadata:
        handler_name    : Core Media Video
        vendor_id       : [0][0][0][0]
        encoder         : Lavc60.31.102 libx264
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
Press [q] to stop, [?] for help
[libx264 @ 0x55562337f990] using cpu capabilities: ARMv8 NEON
[libx264 @ 0x55562337f990] profile High, level 4.0, 4:2:0, 8-bit
[libx264 @ 0x55562337f990] 264 - core 164 r3108 31e19f9 - H.264/MPEG-4 AVC codec - Copyleft 2003-2023 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=6 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=22.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to '/home/sebas/work/projects/ballbox/public/machine-assets/2601070188/ImageScreen/14597490_1080x1920_30fps.mp4':
  Metadata:
    major_brand     : iso5
    minor_version   : 512
    compatible_brands: iso5iso6mp41
    encoder         : Lavf61.7.100
  Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1080x1920, q=2-31, 30 fps, 15360 tbn (default)
      Metadata:
        handler_name    : Core Media Video
        vendor_id       : [0][0][0][0]
        encoder         : Lavc61.19.101 libx264
      Side data:
        cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A
frame=    3 fps=0.7 q=28.0 size=       0KiB time=00:00:00.03 bitrate=  11.5kbits/s speed=0.0083x
frame=    5 fps=1.1 q=28.0 size=       0KiB time=00:00:00.10 bitrate=   3.8kbits/s speed=0.0221x
frame=   11 fps=2.2 q=25.0 size=       0KiB time=00:00:00.30 bitrate=   1.3kbits/s speed=0.0598x
frame=   16 fps=2.9 q=28.0 size=     256KiB time=00:00:00.46 bitrate=4494.7kbits/s speed=0.0846x
frame=   17 fps=2.8 q=28.0 size=     256KiB time=00:00:00.50 bitrate=4195.1kbits/s speed=0.0831x
frame=   21 fps=3.2 q=28.0 size=     256KiB time=00:00:00.63 bitrate=3311.9kbits/s speed=0.0971x
frame=   22 fps=3.1 q=28.0 size=     256KiB time=00:00:00.66 bitrate=3146.3kbits/s speed=0.0949x
frame=   27 fps=3.6 q=28.0 size=     512KiB time=00:00:00.83 bitrate=5033.6kbits/s speed=0.111x
frame=   33 fps=4.1 q=28.0 size=     512KiB time=00:00:01.03 bitrate=4059.4kbits/s speed=0.129x
frame=   36 fps=4.2 q=28.0 size=     512KiB time=00:00:01.13 bitrate=3701.2kbits/s speed=0.133x
frame=   42 fps=4.7 q=28.0 size=     768KiB time=00:00:01.33 bitrate=4718.9kbits/s speed=0.148x
frame=   45 fps=4.7 q=28.0 size=     768KiB time=00:00:01.46 bitrate=4289.9kbits/s speed=0.154x
frame=   49 fps=4.9 q=28.0 size=     768KiB time=00:00:01.56 bitrate=4016.1kbits/s speed=0.156x
frame=   53 fps=5.0 q=25.0 size=     768KiB time=00:00:01.70 bitrate=3701.1kbits/s speed=0.161x
frame=   56 fps=5.1 q=28.0 size=    1024KiB time=00:00:01.80 bitrate=4660.6kbits/s speed=0.163x
frame=   62 fps=5.4 q=28.0 size=    1024KiB time=00:00:02.00 bitrate=4194.5kbits/s speed=0.173x
frame=   65 fps=5.4 q=28.0 size=    1024KiB time=00:00:02.10 bitrate=3994.8kbits/s speed=0.175x
frame=   71 fps=5.7 q=28.0 size=    1024KiB time=00:00:02.30 bitrate=3647.4kbits/s speed=0.184x
frame=   74 fps=5.7 q=28.0 size=    1024KiB time=00:00:02.40 bitrate=3495.4kbits/s speed=0.184x
frame=   80 fps=5.9 q=28.0 size=    1280KiB time=00:00:02.60 bitrate=4033.1kbits/s speed=0.192x
frame=   84 fps=6.0 q=28.0 size=    1280KiB time=00:00:02.73 bitrate=3836.4kbits/s speed=0.195x
frame=   86 fps=5.9 q=28.0 size=    1280KiB time=00:00:02.80 bitrate=3745.1kbits/s speed=0.193x
frame=   91 fps=6.1 q=28.0 size=    1536KiB time=00:00:02.96 bitrate=4241.6kbits/s speed=0.197x
frame=   95 fps=6.1 q=28.0 size=    1536KiB time=00:00:03.10 bitrate=4059.1kbits/s speed= 0.2x
frame=   98 fps=6.1 q=28.0 size=    1536KiB time=00:00:03.20 bitrate=3932.3kbits/s speed= 0.2x
frame=  103 fps=6.2 q=28.0 size=    1536KiB time=00:00:03.36 bitrate=3737.6kbits/s speed=0.204x
frame=  107 fps=6.3 q=28.0 size=    1792KiB time=00:00:03.50 bitrate=4194.4kbits/s speed=0.205x
frame=  111 fps=6.3 q=28.0 size=    1792KiB time=00:00:03.63 bitrate=4040.5kbits/s speed=0.207x
frame=  115 fps=6.4 q=28.0 size=    1792KiB time=00:00:03.76 bitrate=3897.5kbits/s speed=0.209x
frame=  119 fps=6.4 q=28.0 size=    2048KiB time=00:00:03.90 bitrate=4301.9kbits/s speed=0.21x
frame=  124 fps=6.5 q=28.0 size=    2048KiB time=00:00:04.06 bitrate=4125.6kbits/s speed=0.214x
frame=  128 fps=6.5 q=28.0 size=    2048KiB time=00:00:04.20 bitrate=3994.7kbits/s speed=0.215x
frame=  131 fps=6.5 q=28.0 size=    2304KiB time=00:00:04.30 bitrate=4389.5kbits/s speed=0.215x
frame=  136 fps=6.6 q=28.0 size=    2304KiB time=00:00:04.46 bitrate=4225.7kbits/s speed=0.217x
frame=  140 fps=6.7 q=28.0 size=    2304KiB time=00:00:04.60 bitrate=4103.2kbits/s speed=0.219x
frame=  144 fps=6.7 q=28.0 size=    2304KiB time=00:00:04.73 bitrate=3987.6kbits/s speed=0.22x
frame=  147 fps=6.7 q=28.0 size=    2560KiB time=00:00:04.83 bitrate=4339.0kbits/s speed=0.219x
frame=  152 fps=6.7 q=28.0 size=    2560KiB time=00:00:05.00 bitrate=4194.4kbits/s speed=0.222x
frame=  156 fps=6.8 q=28.0 size=    2560KiB time=00:00:05.13 bitrate=4085.4kbits/s speed=0.223x
frame=  160 fps=6.8 q=28.0 size=    2816KiB time=00:00:05.26 bitrate=4380.2kbits/s speed=0.224x
frame=  163 fps=6.8 q=28.0 size=    2816KiB time=00:00:05.36 bitrate=4298.6kbits/s speed=0.223x
frame=  166 fps=6.8 q=28.0 size=    2816KiB time=00:00:05.46 bitrate=4219.9kbits/s speed=0.223x
frame=  170 fps=6.8 q=28.0 size=    2816KiB time=00:00:05.60 bitrate=4119.5kbits/s speed=0.223x
frame=  172 fps=6.7 q=28.0 size=    2816KiB time=00:00:05.66 bitrate=4071.0kbits/s speed=0.222x
frame=  178 fps=6.8 q=28.0 size=    3072KiB time=00:00:05.86 bitrate=4289.7kbits/s speed=0.225x
frame=  179 fps=6.7 q=28.0 size=    3072KiB time=00:00:05.90 bitrate=4265.5kbits/s speed=0.222x
frame=  182 fps=6.7 q=28.0 size=    3072KiB time=00:00:06.00 bitrate=4194.4kbits/s speed=0.222x
frame=  187 fps=6.8 q=28.0 size=    3328KiB time=00:00:06.16 bitrate=4421.1kbits/s speed=0.224x
frame=  188 fps=6.7 q=28.0 size=    3328KiB time=00:00:06.20 bitrate=4397.3kbits/s speed=0.221x
frame=  192 fps=6.7 q=28.0 size=    3328KiB time=00:00:06.33 bitrate=4304.7kbits/s speed=0.222x
frame=  196 fps=6.7 q=28.0 size=    3328KiB time=00:00:06.46 bitrate=4216.0kbits/s speed=0.222x
frame=  202 fps=6.8 q=28.0 size=    3584KiB time=00:00:06.66 bitrate=4404.1kbits/s speed=0.225x
frame=  206 fps=6.9 q=28.0 size=    3584KiB time=00:00:06.80 bitrate=4317.7kbits/s speed=0.226x
frame=  211 fps=6.9 q=28.0 size=    3584KiB time=00:00:06.96 bitrate=4214.4kbits/s speed=0.228x
frame=  213 fps=6.9 q=28.0 size=    3584KiB time=00:00:07.03 bitrate=4174.5kbits/s speed=0.226x
frame=  218 fps=6.9 q=28.0 size=    3840KiB time=00:00:07.20 bitrate=4369.1kbits/s speed=0.228x
frame=  219 fps=6.8 q=28.0 size=    3840KiB time=00:00:07.23 bitrate=4349.0kbits/s speed=0.226x
frame=  224 fps=6.9 q=28.0 size=    3840KiB time=00:00:07.40 bitrate=4251.0kbits/s speed=0.227x
frame=  226 fps=6.8 q=28.0 size=    4096KiB time=00:00:07.46 bitrate=4493.9kbits/s speed=0.226x
frame=  231 fps=6.9 q=28.0 size=    4096KiB time=00:00:07.63 bitrate=4395.8kbits/s speed=0.227x
frame=  234 fps=6.9 q=28.0 size=    4096KiB time=00:00:07.73 bitrate=4339.0kbits/s speed=0.227x
frame=  236 fps=6.8 q=25.0 size=    4096KiB time=00:00:07.80 bitrate=4301.9kbits/s speed=0.225x
frame=  243 fps=6.9 q=28.0 size=    4352KiB time=00:00:08.03 bitrate=4438.0kbits/s speed=0.229x
frame=  245 fps=6.9 q=28.0 size=    4352KiB time=00:00:08.10 bitrate=4401.5kbits/s speed=0.228x
frame=  250 fps=6.9 q=28.0 size=    4352KiB time=00:00:08.26 bitrate=4312.7kbits/s speed=0.229x
frame=  252 fps=6.9 q=28.0 size=    4352KiB time=00:00:08.33 bitrate=4278.2kbits/s speed=0.228x
frame=  256 fps=6.9 q=25.0 size=    4608KiB time=00:00:08.46 bitrate=4458.6kbits/s speed=0.228x
frame=  261 fps=6.9 q=28.0 size=    4608KiB time=00:00:08.63 bitrate=4372.5kbits/s speed=0.23x
frame=  263 fps=6.9 q=28.0 size=    4608KiB time=00:00:08.70 bitrate=4339.0kbits/s speed=0.228x
frame=  269 fps=7.0 q=25.0 size=    4864KiB time=00:00:08.90 bitrate=4477.1kbits/s speed=0.231x
frame=  273 fps=7.0 q=28.0 size=    4864KiB time=00:00:09.03 bitrate=4411.0kbits/s speed=0.231x
frame=  278 fps=7.0 q=28.0 size=    5120KiB time=00:00:09.20 bitrate=4559.1kbits/s speed=0.232x
frame=  280 fps=7.0 q=28.0 size=    5120KiB time=00:00:09.26 bitrate=4526.3kbits/s speed=0.231x
frame=  286 fps=7.0 q=28.0 size=    5376KiB time=00:00:09.46 bitrate=4652.2kbits/s speed=0.233x
frame=  288 fps=7.0 q=28.0 size=    5376KiB time=00:00:09.53 bitrate=4619.6kbits/s speed=0.232x
frame=  292 fps=7.0 q=28.0 size=    5376KiB time=00:00:09.66 bitrate=4555.9kbits/s speed=0.232x
frame=  296 fps=7.0 q=28.0 size=    5632KiB time=00:00:09.80 bitrate=4707.9kbits/s speed=0.233x
frame=  301 fps=7.1 q=28.0 size=    5632KiB time=00:00:09.96 bitrate=4629.2kbits/s speed=0.234x
frame=  305 fps=7.1 q=28.0 size=    5632KiB time=00:00:10.10 bitrate=4568.1kbits/s speed=0.234x
frame=  310 fps=7.1 q=28.0 size=    5632KiB time=00:00:10.26 bitrate=4493.9kbits/s speed=0.235x
frame=  314 fps=7.1 q=28.0 size=    5888KiB time=00:00:10.40 bitrate=4638.0kbits/s speed=0.236x
frame=  318 fps=7.1 q=28.0 size=    5888KiB time=00:00:10.53 bitrate=4579.3kbits/s speed=0.236x
frame=  321 fps=7.1 q=28.0 size=    5888KiB time=00:00:10.63 bitrate=4536.2kbits/s speed=0.236x
frame=  324 fps=7.1 q=28.0 size=    5888KiB time=00:00:10.73 bitrate=4493.9kbits/s speed=0.235x
frame=  328 fps=7.1 q=28.0 size=    6144KiB time=00:00:10.86 bitrate=4631.8kbits/s speed=0.236x
frame=  332 fps=7.1 q=28.0 size=    6144KiB time=00:00:11.00 bitrate=4575.6kbits/s speed=0.236x
frame=  336 fps=7.1 q=28.0 size=    6144KiB time=00:00:11.13 bitrate=4520.8kbits/s speed=0.236x
frame=  341 fps=7.2 q=25.0 size=    6144KiB time=00:00:11.30 bitrate=4454.2kbits/s speed=0.237x
frame=  346 fps=7.2 q=28.0 size=    6400KiB time=00:00:11.46 bitrate=4572.3kbits/s speed=0.238x
frame=  348 fps=7.2 q=28.0 size=    6400KiB time=00:00:11.56 bitrate=4532.8kbits/s speed=0.238x
frame=  354 fps=7.2 q=28.0 size=    6400KiB time=00:00:11.73 bitrate=4468.4kbits/s speed=0.239x
frame=  358 fps=7.2 q=28.0 size=    6656KiB time=00:00:11.86 bitrate=4594.9kbits/s speed=0.239x
frame=  364 fps=7.3 q=28.0 size=    6656KiB time=00:00:12.06 bitrate=4518.8kbits/s speed=0.241x
frame=  367 fps=7.2 q=28.0 size=    6656KiB time=00:00:12.16 bitrate=4481.6kbits/s speed=0.24x
frame=  371 fps=7.3 q=25.0 size=    6912KiB time=00:00:12.30 bitrate=4603.5kbits/s speed=0.241x
frame=  379 fps=7.3 q=28.0 size=    6912KiB time=00:00:12.56 bitrate=4505.8kbits/s speed=0.243x
frame=  384 fps=7.4 q=28.0 size=    6912KiB time=00:00:12.73 bitrate=4446.9kbits/s speed=0.244x
frame=  391 fps=7.4 q=28.0 size=    7168KiB time=00:00:12.96 bitrate=4528.6kbits/s speed=0.246x
frame=  399 fps=7.5 q=28.0 size=    7168KiB time=00:00:13.23 bitrate=4437.3kbits/s speed=0.249x
frame=  407 fps=7.6 q=28.0 size=    7424KiB time=00:00:13.50 bitrate=4505.0kbits/s speed=0.252x
frame=  415 fps=7.7 q=28.0 size=    7424KiB time=00:00:13.76 bitrate=4417.8kbits/s speed=0.254x
frame=  423 fps=7.7 q=28.0 size=    7680KiB time=00:00:14.03 bitrate=4483.3kbits/s speed=0.257x
[mp4 @ 0x555623390700] Starting second pass: moving the moov atom to the beginning of the file
[out#0/mp4 @ 0x555623390630] video:7960KiB audio:0KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.062789%
frame=  432 fps=7.8 q=-1.0 Lsize=    7965KiB time=00:00:14.33 bitrate=4552.3kbits/s speed=0.26x
[libx264 @ 0x55562337f990] frame I:24    Avg QP:19.09  size: 31160
[libx264 @ 0x55562337f990] frame P:198   Avg QP:21.73  size: 22831
[libx264 @ 0x55562337f990] frame B:210   Avg QP:22.72  size: 13724
[libx264 @ 0x55562337f990] consecutive B-frames: 31.2%  7.4% 13.2% 48.1%
[libx264 @ 0x55562337f990] mb I  I16..4: 37.1% 59.6%  3.3%
[libx264 @ 0x55562337f990] mb P  I16..4: 22.2% 34.0%  1.0%  P16..4: 25.1%  3.7%  1.6%  0.0%  0.0%    skip:12.5%
[libx264 @ 0x55562337f990] mb B  I16..4:  2.8%  4.0%  0.2%  B16..8: 36.0%  4.9%  0.5%  direct: 3.0%  skip:48.6%  L0:47.8% L1:49.1% BI: 3.1%
[libx264 @ 0x55562337f990] 8x8 transform intra:59.3% inter:94.3%
[libx264 @ 0x55562337f990] coded y,uvDC,uvAC intra: 26.3% 37.2% 1.1% inter: 12.4% 16.8% 0.0%
[libx264 @ 0x55562337f990] i16 v,h,dc,p: 25% 27%  9% 39%
[libx264 @ 0x55562337f990] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 25% 23% 30%  3%  4%  4%  4%  4%  3%
[libx264 @ 0x55562337f990] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 24% 25% 17%  5%  9%  7%  6%  5%  3%
[libx264 @ 0x55562337f990] i8c dc,h,v,p: 63% 18% 17%  1%
[libx264 @ 0x55562337f990] Weighted P-Frames: Y:2.5% UV:1.0%
[libx264 @ 0x55562337f990] ref P L0: 77.1%  5.8% 12.5%  4.5%  0.1%
[libx264 @ 0x55562337f990] ref B L0: 92.9%  5.6%  1.5%
[libx264 @ 0x55562337f990] ref B L1: 98.0%  2.0%
[libx264 @ 0x55562337f990] kb/s:4528.02
-rw-r--r-- 1 sebas sebas 7.8M Jun  8 17:25 /home/sebas/work/projects/ballbox/public/machine-assets/2601070188/ImageScreen/14597490_1080x1920_30fps.mp4
{
    "programs": [

    ],
    "stream_groups": [

    ],
    "streams": [
        {
            "codec_name": "h264",
            "width": 1080,
            "height": 1920,
            "avg_frame_rate": "30/1"
        }
    ],
    "format": {
        "duration": "14.400000",
        "size": "8156239"
    }
}
5b350d614e0eb24e5c683fbdb4307bdc8f5a8c267ae3db05bdcac5e1728731f0  /home/sebas/work/projects/ballbox/public/machine-assets/2601070188/ImageScreen/14597490_1080x1920_30fps.mp4


Successfully replaced 1 block(s) in /home/sebas/work/projects/ballbox/data/machine-ads/2601070188.json.

    ...
  9       "publicPath": "/machine-assets/2601070188/VideoAndImageAd/See You Again (Cover)--音悦Tai.mp4",
 10       "restartRequired": "app"
 11     },
 12     {
-13       "target": "ImageScreen/14597490_720x1280_30fps.mp4",
-14       "publicPath": "/machine-assets/2601070188/ImageScreen/14597490_720x1280_30fps.mp4",
+13       "target": "ImageScreen/14597490_1080x1920_30fps.mp4",
+14       "publicPath": "/machine-assets/2601070188/ImageScreen/14597490_1080x1920_30fps.mp4",
 15       "restartRequired": "app"
 16     }
 17   ]
 18 }

--- /home/sebas/work/projects/ballbox/data/machine-ads/2601070188.json
+++ /home/sebas/work/projects/ballbox/data/machine-ads/2601070188.json
@@ -9,10 +9,10 @@
       "publicPath": "/machine-assets/2601070188/VideoAndImageAd/See You Again (Cover)--音悦Tai.mp4",
       "restartRequired": "app"
     },
     {
-      "target": "ImageScreen/14597490_720x1280_30fps.mp4",
-      "publicPath": "/machine-assets/2601070188/ImageScreen/14597490_720x1280_30fps.mp4",
+      "target": "ImageScreen/14597490_1080x1920_30fps.mp4",
+      "publicPath": "/machine-assets/2601070188/ImageScreen/14597490_1080x1920_30fps.mp4",
       "restartRequired": "app"
     }
   ]
 }


bash

cd /home/sebas/work/projects/ballbox && git add data/machine-ads/2601070188.json 'public/machine-assets/2601070188/ImageScreen/14597490_1080x1920_30fps.mp4' && git commit -m 'Raise fullscreen test video quality at 30fps' && git push origin main


[main fd2c2c2] Raise fullscreen test video quality at 30fps
 2 files changed, 2 insertions(+), 2 deletions(-)
 create mode 100644 public/machine-assets/2601070188/ImageScreen/14597490_1080x1920_30fps.mp4
pre-push: pushing main, running quality checks...
$ node scripts/check-doc-references.mjs
Docs reference check passed for README.md, PLAN.md, and docs/index.md
$ ./scripts/db-local-up.sh
Local Postgres already ready.
$ ./scripts/prisma-migrate-deploy.sh
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "ballbox_local", schema "public" at "127.0.0.1:5432"

2 migrations found in prisma/migrations

No pending migrations to apply.
$ ./scripts/prisma-check-migrations.sh
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "ballbox_local", schema "public" at "127.0.0.1:5432"

2 migrations found in prisma/migrations

Database schema is up to date!
Prisma schema loaded from prisma/schema.prisma
The schema at prisma/schema.prisma is valid 🚀
$ eslint .
$ rm -rf .next/types .next/dev/types
$ tsc --noEmit --incremental false
$ vitest run tests/contracts

 RUN  v4.1.0 /home/sebas/work/projects/ballbox

 ✓ tests/contracts/network/network-admin-venue-card.test.tsx (2 tests) 514ms
     ✓ updates the targeted machine active flag through setClubs  390ms
 ✓ tests/contracts/classes/classes-request-form.test.tsx (4 tests) 977ms
     ✓ submits the selected visible slot as part of the request  552ms
 ✓ tests/contracts/players/players-admin-player-card.test.tsx (2 tests) 391ms
 ✓ tests/contracts/weekly-availability-grid.test.tsx (2 tests) 3235ms
     ✓ exposes focusable button semantics for keyboard users and toggles an open slot  2047ms
     ✓ marks closed slots as aria-disabled and ignores pointer interaction  1185ms
 ✓ tests/contracts/players/players-admin-create-player-section.test.tsx (1 test) 426ms
     ✓ renders the extracted section shell and forwards player form updates  424ms
 ✓ tests/contracts/coaches/backend.test.ts (1 test) 271ms
 ✓ tests/contracts/clubs/routes.test.ts (9 tests) 361ms
 ✓ tests/contracts/coaches/routes.test.ts (7 tests) 294ms
 ✓ tests/contracts/payments/auth.test.ts (2 tests) 307ms
 ✓ tests/contracts/accounts/routes.test.ts (3 tests) 240ms
 ✓ tests/contracts/coaches/students-routes.test.ts (5 tests) 239ms
 ✓ tests/contracts/tvs/backend-modules.test.ts (14 tests) 194ms
 ✓ tests/contracts/tvs/admin-routes.test.ts (7 tests) 306ms
 ✓ tests/contracts/players/admin-routes.test.ts (9 tests) 218ms
 ✓ tests/contracts/network/routes.test.ts (12 tests) 203ms
 ✓ tests/contracts/tvs/routes.test.ts (10 tests) 290ms
 ✓ tests/contracts/payments/admin-routes.test.ts (6 tests) 220ms
 ✓ tests/contracts/payments/orders-route.test.ts (2 tests) 176ms
 ✓ tests/contracts/tvs/screen-player.test.tsx (3 tests) 247ms
 ✓ tests/contracts/sports/routes.test.ts (8 tests) 149ms
 ✓ tests/contracts/classes/routes.test.ts (5 tests) 189ms
 ✓ tests/contracts/players/backend-modules.test.ts (3 tests) 92ms
 ✓ tests/contracts/players/routes.test.ts (1 test) 153ms
 ✓ tests/contracts/network/backend-modules.test.ts (6 tests) 61ms
 ✓ tests/contracts/network/network-admin-club-card.test.tsx (2 tests) 180ms
 ✓ tests/contracts/network/network-admin-shell.test.tsx (1 test) 129ms
 ✓ tests/contracts/players/players-admin-stats.test.tsx (1 test) 91ms
 ✓ tests/contracts/tvs/backend-runtime.test.ts (4 tests) 108ms
 ✓ tests/contracts/players/players-admin-player-list.test.tsx (2 tests) 81ms
 ✓ tests/contracts/network/network-admin-create-club-section.test.tsx (1 test) 69ms
 ✓ tests/contracts/classes/by-date.test.ts (1 test) 7ms
 ✓ tests/contracts/players/players-admin-shell.test.tsx (1 test) 50ms
 ✓ tests/contracts/network/network-admin-club-list.test.tsx (1 test) 44ms

 Test Files  33 passed (33)
      Tests  138 passed (138)
   Start at  17:26:38
   Duration  15.38s (transform 2.75s, setup 0ms, import 6.39s, tests 10.51s, environment 18.79s)

$ node scripts/next-build-safe.mjs
[build] linux/arm64 detected: using webpack + SWC wasm fallback to avoid native next-swc crash
⚠ experimental.useWasmBinary is not an option for supported platform linux/arm64 and will be ignored.
  Skipping creating a lockfile at /home/sebas/work/projects/ballbox/.next/lock because we're using WASM bindings
▲ Next.js 16.2.1 (webpack)
- Environments: .env.local, .env.production

  Creating an optimized production build ...
⚠ experimental.useWasmBinary is not an option for supported platform linux/arm64 and will be ignored.
⚠ experimental.useWasmBinary is not an option for supported platform linux/arm64 and will be ignored.
⚠ experimental.useWasmBinary is not an option for supported platform linux/arm64 and will be ignored.
✓ Compiled successfully in 9.6s
  Skipping validation of types
  Finished TypeScript config validation in 9ms ...
  Collecting page data using 3 workers ...
  Generating static pages using 3 workers (0/56) ...
⚠ experimental.useWasmBinary is not an option for supported platform linux/arm64 and will be ignored.
⚠ experimental.useWasmBinary is not an option for supported platform linux/arm64 and will be ignored.
⚠ experimental.useWasmBinary is not an option for supported platform linux/arm64 and will be ignored.
  Generating static pages using 3 workers (14/56)
  Generating static pages using 3 workers (28/56)
  Generating static pages using 3 workers (42/56)
✓ Generating static pages using 3 workers (56/56) in 1251ms
  Finalizing page optimization ...
  Collecting build traces ...

Route (app)
┌ ○ /
├ ○ /_not-found
├ ƒ /admin
├ ƒ /admin/login
├ ƒ /admin/network
├ ƒ /admin/payments
├ ƒ /admin/players
├ ƒ /admin/screens
├ ƒ /admin/sports
├ ƒ /admin/tvs
├ ƒ /api/account/session
├ ƒ /api/admin/logout
├ ƒ /api/admin/payments/operations
├ ƒ /api/admin/payments/sessions
├ ƒ /api/admin/payments/sessions/[sessionId]
├ ƒ /api/admin/players
├ ƒ /api/admin/players/[playerId]
├ ƒ /api/admin/players/[playerId]/memberships
├ ƒ /api/admin/players/memberships/[membershipId]
├ ƒ /api/admin/session
├ ƒ /api/admin/sports/classes
├ ƒ /api/admin/sports/classes/[classId]
├ ƒ /api/admin/sports/coaches
├ ƒ /api/admin/sports/coaches/[coachId]
├ ƒ /api/admin/sports/open-matches
├ ƒ /api/admin/sports/open-matches/[matchId]
├ ƒ /api/admin/sports/operations
├ ƒ /api/admin/summary
├ ƒ /api/admin/tvs/assignments/[assignmentId]
├ ƒ /api/admin/tvs/campaigns
├ ƒ /api/admin/tvs/campaigns/[campaignId]
├ ƒ /api/admin/tvs/campaigns/[campaignId]/assignments
├ ƒ /api/admin/tvs/campaigns/[campaignId]/creatives
├ ƒ /api/admin/tvs/creatives/[creativeId]
├ ƒ /api/admin/tvs/operations
├ ƒ /api/admin/tvs/screens
├ ƒ /api/admin/tvs/screens/[screenId]
├ ƒ /api/admin/tvs/tv-devices
├ ƒ /api/admin/tvs/tv-devices/[tvDeviceId]
├ ƒ /api/atc-public/availability/sportclubs/[sportclubId]
├ ƒ /api/classes/logout
├ ƒ /api/classes/offers
├ ƒ /api/classes/offers/[offerId]
├ ƒ /api/classes/requests
├ ƒ /api/classes/session
├ ƒ /api/clubs/accounts
├ ƒ /api/clubs/coaches
├ ƒ /api/clubs/coaches/[coachId]
├ ƒ /api/clubs/invites
├ ƒ /api/clubs/logout
├ ƒ /api/clubs/manual-classes
├ ƒ /api/clubs/me
├ ƒ /api/clubs/players
├ ƒ /api/clubs/session
├ ƒ /api/clubs/venues
├ ƒ /api/clubs/venues/[venueId]
├ ƒ /api/coaches/accounts
├ ƒ /api/coaches/availability
├ ƒ /api/coaches/clubs
├ ƒ /api/coaches/invites/[token]
├ ƒ /api/coaches/logout
├ ƒ /api/coaches/me
├ ƒ /api/coaches/session
├ ƒ /api/coaches/students
├ ƒ /api/coaches/students/[bookingId]
├ ƒ /api/coaches/students/players
├ ƒ /api/coaches/students/players/[playerId]
├ ƒ /api/integrations/payments/approved
├ ƒ /api/integrations/payments/health
├ ƒ /api/integrations/payments/orders
├ ƒ /api/integrations/payments/sessions
├ ƒ /api/machines/[machineId]/ads-manifest
├ ƒ /api/network
├ ƒ /api/network/[clubId]
├ ƒ /api/network/[clubId]/venues
├ ƒ /api/network/[clubId]/venues/[venueId]
├ ƒ /api/network/venues/[venueId]/vending-machines
├ ƒ /api/network/venues/[venueId]/vending-machines/[vendingMachineId]
├ ƒ /api/players
├ ƒ /api/sports
├ ƒ /api/tvs/health
├ ƒ /api/tvs/heartbeat
├ ƒ /api/tvs/impression
├ ƒ /api/tvs/manifest/[screenId]
├ ƒ /api/tvs/screens
├ ƒ /classes
├ ƒ /classes-by-date
├ ƒ /classes/[offerId]
├ ƒ /classes/login
├ ƒ /classes/me
├ ƒ /clubs
├ ƒ /clubs/coaches
├ ƒ /clubs/venues/[venueId]
├ ○ /coaches
├ ƒ /coaches/settings
├ ○ /manifest.webmanifest
├ ƒ /notification/mercadopago
├ ○ /offline
└ ƒ /player/[screenId]

ƒ Proxy (Middleware)

○  (Static)   prerendered as static content
ƒ  (Dynamic)  server-rendered on demand

pre-push: all checks passed.
To https://github.com/sebasfavaron/ballbox.git
   7fb5e67..fd2c2c2  main -> main


y persisti todo en el rfc que cierro sesion y arranco esa implementacion ya (sobre lo de reiniciar app o sistema que hayan ambos botones)
y que sea ademas de un proceso que corre 10s despues del boot y despues periodicamente que ademas quede el menu accesible de algun lado


**Updating RFC Implementation**

I need to update the RFC with my findings and the desired implementation. This includes incorporating buttons for restarting the app and system, plus a feature for periodic checks after boot, possibly 10 seconds later. I’m also considering making the menu accessible and wondering if saving memory would be beneficial. Overall, I want to ensure that this documentation effectively captures all these elements. Let’s make this clear and organized!

edit

## Reality confirmed on device
- Installed sidecar can sync successfully on Android 7.1.2 once `minSdk` and storage behavior are fixed.
- Correct target root on the machine is `/sdcard/TcnFolder`.
- `ImageScreen/` is the fullscreen standby slot.
- `VideoAndImageAd/` is the smaller top video slot.
- Both folders accept looped video files.
- Current sidecar prune behavior can delete stale files inside managed folders.
- Freshly synced media may require restarting the main vending app or rebooting Android before visible playback updates reliably apply.
- High-resolution/high-fps fullscreen video can decode poorly on the machine; a 2160x3840 60fps test clip played in slow motion for the first seconds, so practical delivery profiles must be constrained to device-safe formats.

## Reality confirmed on device
- Installed sidecar can sync successfully on Android 7.1.2 once `minSdk` and storage behavior are fixed.
- Correct target root on the machine is `/sdcard/TcnFolder`.
- `ImageScreen/` is the fullscreen standby slot.
- `VideoAndImageAd/` is the smaller top video slot.
- Both folders accept looped video files.
- Current sidecar prune behavior can delete stale files inside managed folders.
- Freshly synced media may require restarting the main vending app or rebooting Android before visible playback updates reliably apply.
- The implementation plan should assume both actions are useful: restart vending app and reboot Android.
- High-resolution/high-fps fullscreen video can decode poorly on the machine; a 2160x3840 60fps test clip played in slow motion for the first seconds.
- A safer fullscreen profile worked better operationally: 30fps with lower decode load. Current compromise test moved from 720x1280 30fps to a higher-quality 1080x1920 30fps version to preserve visual quality while staying below the failing 60fps profile.

## Target state
Ballbox should own a per-machine desired state model.
The sidecar should only:
1. fetch manifest
2. download listed files
3. verify hashes
4. write exact target paths
5. prune stale files inside managed directories

Changing content should mean changing Ballbox backend state, not Android code.

## Target state
Ballbox should own a per-machine desired state model.
The sidecar should:
1. wait ~10 seconds after boot before first sync
2. fetch manifest
3. download listed files
4. verify hashes
5. write exact target paths
6. prune stale files inside managed directories
7. continue periodic sync afterward
8. keep a manual operator menu accessible at all times from some discoverable place

Changing content should mean changing Ballbox backend state, not Android code.

## Rollout plan
### Phase 1
- move hardcoded manifest config into file-backed JSON
- expose `managedDirs` and `targetRootHint` in manifest
- update sidecar default target root to `/sdcard/TcnFolder`
- keep sidecar reinstalls rare

### Phase 2
- add admin mutation path in Ballbox backend
- validate target paths against allowed machine directories
- allow add/replace/remove entries per machine

### Phase 3
- add upload flow and stored asset references
- optionally track asset history and rollback

## Rollout plan
### Phase 1
- move hardcoded manifest config into file-backed JSON
- expose `managedDirs` and `targetRootHint` in manifest
- update sidecar default target root to `/sdcard/TcnFolder`
- keep sidecar reinstalls rare

### Phase 2
- sidecar runs automatically after boot with ~10 second delay
- sidecar repeats sync periodically in background
- sidecar keeps a manual operator menu reachable from an accessible entrypoint instead of hiding sync behind install-time flows
- operator menu includes at least:
  - sync now
  - open logs/status
  - restart vending app
  - reboot Android system

### Phase 3
- add admin mutation path in Ballbox backend
- validate target paths against allowed machine directories
- allow add/replace/remove entries per machine
- add upload flow and stored asset references
- optionally track asset history and rollback

## Safety constraints
- prune only inside explicitly managed directories
- never allow arbitrary absolute target paths from user input
- validate machine target prefixes against allowlist
- keep manifest truthful: only list assets that exist and hash correctly
- operator UX must make restart/reboot requirements explicit when runtime cache prevents hot swap
- reboot action is irreversible enough operationally that the UI should make intent obvious and avoid accidental taps

## Immediate implementation steps
1. add machine config JSON files under repo data directory
2. refactor manifest builder to read config instead of hardcoded map
3. include `managedDirs` and `targetRootHint` in manifest response
4. update Android sidecar default root to `/sdcard/TcnFolder`
5. constrain fullscreen transcode defaults to machine-safe profiles like 24/30fps and lower resolution instead of assuming source originals are decodable in real time
6. later add admin write path

## Immediate implementation steps
1. add machine config JSON files under repo data directory
2. refactor manifest builder to read config instead of hardcoded map
3. include `managedDirs` and `targetRootHint` in manifest response
4. update Android sidecar default root to `/sdcard/TcnFolder`
5. constrain fullscreen transcode defaults to machine-safe profiles like 24/30fps and lower resolution instead of assuming source originals are decodable in real time
6. add boot receiver / startup path that waits ~10 seconds before first sync
7. add periodic background sync scheduling
8. add persistent operator-accessible menu entry with restart-app and reboot-system actions
9. later add admin write path


Successfully replaced 5 block(s) in /home/sebas/work/projects/ballbox/docs/tcn-api-driven-machine-ads-rfc-2026-06-08.md.

     ...
  10 - `VideoAndImageAd/` is the smaller top video slot.
  11 - Both folders accept looped video files.
  12 - Current sidecar prune behavior can delete stale files inside managed folders.
  13 - Freshly synced media may require restarting the main vending app or rebooting Android before visible playback updates reliably apply.
- 14 - High-resolution/high-fps fullscreen video can decode poorly on the machine; a 2160x3840 60fps test clip played in slow motion for the first seconds, so practical delivery profiles must be constrained to device-safe formats.
+ 14 - The implementation plan should assume both actions are useful: restart vending app and reboot Android.
+ 15 - High-resolution/high-fps fullscreen video can decode poorly on the machine; a 2160x3840 60fps test clip played in slow motion for the first seconds.
+ 16 - A safer fullscreen profile worked better operationally: 30fps with lower decode load. Current compromise test moved from 720x1280 30fps to a higher-quality 1080x1920 30fps version to preserve visual quality while staying below the failing 60fps profile.
  15
  16 ## Problem with current MVP
  17 Current backend manifest generation is hardcoded in `lib/machine-ads-manifest.ts`.
  18 That means every content change currently needs a code edit and deploy.
  19 This is too slow for operator use and does not scale to arbitrary file replacement/prune.
  20
  21 ## Target state
  22 Ballbox should own a per-machine desired state model.
- 23 The sidecar should only:
- 24 1. fetch manifest
- 25 2. download listed files
- 26 3. verify hashes
- 27 4. write exact target paths
- 28 5. prune stale files inside managed directories
+ 25 The sidecar should:
+ 26 1. wait ~10 seconds after boot before first sync
+ 27 2. fetch manifest
+ 28 3. download listed files
+ 29 4. verify hashes
+ 30 5. write exact target paths
+ 31 6. prune stale files inside managed directories
+ 32 7. continue periodic sync afterward
+ 33 8. keep a manual operator menu accessible at all times from some discoverable place
  29
  30 Changing content should mean changing Ballbox backend state, not Android code.
  31
  32 ## Proposed manifest shape
     ...
  82 - update sidecar default target root to `/sdcard/TcnFolder`
  83 - keep sidecar reinstalls rare
  84
  85 ### Phase 2
+ 91 - sidecar runs automatically after boot with ~10 second delay
+ 92 - sidecar repeats sync periodically in background
+ 93 - sidecar keeps a manual operator menu reachable from an accessible entrypoint instead of hiding sync behind install-time flows
+ 94 - operator menu includes at least:
+ 95   - sync now
+ 96   - open logs/status
+ 97   - restart vending app
+ 98   - reboot Android system
+ 99
+100 ### Phase 3
  86 - add admin mutation path in Ballbox backend
  87 - validate target paths against allowed machine directories
  88 - allow add/replace/remove entries per machine
- 89
- 90 ### Phase 3
  91 - add upload flow and stored asset references
  92 - optionally track asset history and rollback
  93
  94 ## Safety constraints
     ...
  96 - never allow arbitrary absolute target paths from user input
  97 - validate machine target prefixes against allowlist
  98 - keep manifest truthful: only list assets that exist and hash correctly
  99 - operator UX must make restart/reboot requirements explicit when runtime cache prevents hot swap
+113 - reboot action is irreversible enough operationally that the UI should make intent obvious and avoid accidental taps
 100
 101 ## Current implementation decision
 102 Start with a repo-backed config file because it is the cheapest path from hardcoded code to API-driven desired state.
 103 That gives immediate leverage while keeping migration path open to DB/admin UI.
     ...
 107 2. refactor manifest builder to read config instead of hardcoded map
 108 3. include `managedDirs` and `targetRootHint` in manifest response
 109 4. update Android sidecar default root to `/sdcard/TcnFolder`
 110 5. constrain fullscreen transcode defaults to machine-safe profiles like 24/30fps and lower resolution instead of assuming source originals are decodable in real time
-111 6. later add admin write path
+125 6. add boot receiver / startup path that waits ~10 seconds before first sync
+126 7. add periodic background sync scheduling
+127 8. add persistent operator-accessible menu entry with restart-app and reboot-system actions
+128 9. later add admin write path

--- /home/sebas/work/projects/ballbox/docs/tcn-api-driven-machine-ads-rfc-2026-06-08.md
+++ /home/sebas/work/projects/ballbox/docs/tcn-api-driven-machine-ads-rfc-2026-06-08.md
@@ -10,23 +10,28 @@
 - `VideoAndImageAd/` is the smaller top video slot.
 - Both folders accept looped video files.
 - Current sidecar prune behavior can delete stale files inside managed folders.
 - Freshly synced media may require restarting the main vending app or rebooting Android before visible playback updates reliably apply.
-- High-resolution/high-fps fullscreen video can decode poorly on the machine; a 2160x3840 60fps test clip played in slow motion for the first seconds, so practical delivery profiles must be constrained to device-safe formats.
+- The implementation plan should assume both actions are useful: restart vending app and reboot Android.
+- High-resolution/high-fps fullscreen video can decode poorly on the machine; a 2160x3840 60fps test clip played in slow motion for the first seconds.
+- A safer fullscreen profile worked better operationally: 30fps with lower decode load. Current compromise test moved from 720x1280 30fps to a higher-quality 1080x1920 30fps version to preserve visual quality while staying below the failing 60fps profile.

 ## Problem with current MVP
 Current backend manifest generation is hardcoded in `lib/machine-ads-manifest.ts`.
 That means every content change currently needs a code edit and deploy.
 This is too slow for operator use and does not scale to arbitrary file replacement/prune.

 ## Target state
 Ballbox should own a per-machine desired state model.
-The sidecar should only:
-1. fetch manifest
-2. download listed files
-3. verify hashes
-4. write exact target paths
-5. prune stale files inside managed directories
+The sidecar should:
+1. wait ~10 seconds after boot before first sync
+2. fetch manifest
+3. download listed files
+4. verify hashes
+5. write exact target paths
+6. prune stale files inside managed directories
+7. continue periodic sync afterward
+8. keep a manual operator menu accessible at all times from some discoverable place

 Changing content should mean changing Ballbox backend state, not Android code.

 ## Proposed manifest shape
@@ -82,13 +87,21 @@
 - update sidecar default target root to `/sdcard/TcnFolder`
 - keep sidecar reinstalls rare

 ### Phase 2
+- sidecar runs automatically after boot with ~10 second delay
+- sidecar repeats sync periodically in background
+- sidecar keeps a manual operator menu reachable from an accessible entrypoint instead of hiding sync behind install-time flows
+- operator menu includes at least:
+  - sync now
+  - open logs/status
+  - restart vending app
+  - reboot Android system
+
+### Phase 3
 - add admin mutation path in Ballbox backend
 - validate target paths against allowed machine directories
 - allow add/replace/remove entries per machine
-
-### Phase 3
 - add upload flow and stored asset references
 - optionally track asset history and rollback

 ## Safety constraints
@@ -96,8 +109,9 @@
 - never allow arbitrary absolute target paths from user input
 - validate machine target prefixes against allowlist
 - keep manifest truthful: only list assets that exist and hash correctly
 - operator UX must make restart/reboot requirements explicit when runtime cache prevents hot swap
+- reboot action is irreversible enough operationally that the UI should make intent obvious and avoid accidental taps

 ## Current implementation decision
 Start with a repo-backed config file because it is the cheapest path from hardcoded code to API-driven desired state.
 That gives immediate leverage while keeping migration path open to DB/admin UI.
@@ -107,5 +121,8 @@
 2. refactor manifest builder to read config instead of hardcoded map
 3. include `managedDirs` and `targetRootHint` in manifest response
 4. update Android sidecar default root to `/sdcard/TcnFolder`
 5. constrain fullscreen transcode defaults to machine-safe profiles like 24/30fps and lower resolution instead of assuming source originals are decodable in real time
-6. later add admin write path
+6. add boot receiver / startup path that waits ~10 seconds before first sync
+7. add periodic background sync scheduling
+8. add persistent operator-accessible menu entry with restart-app and reboot-system actions
+9. later add admin write path


Listo. Ya quedó persistido en el RFC.

Agregué:
- restart de app principal y reboot del sistema como acciones necesarias
- que ambas deben existir como botones
- sync automático:
  - ~10s después del boot
  - luego periódico
- menú manual siempre accesible desde algún entrypoint visible
- transcode machine-safe como regla de implementación

Doc actualizado:
- `docs/tcn-api-driven-machine-ads-rfc-2026-06-08.md`

Estado útil para próxima sesión:
- target root correcto: `/sdcard/TcnFolder`
- fullscreen: `ImageScreen/`
- top video: `VideoAndImageAd/`
- sync + prune funcionando
- cambios de API ya controlan contenido sin reinstalar APK
- restart app/reboot sigue siendo parte real del flujo visible

Cuando arranques la próxima sesión, ya podés entrar directo a implementar eso.