Skip to content

feat(board): the board art ships beside the files that name it - #952

Closed
ExtraToast wants to merge 1 commit into
mainfrom
feat/board-art-ships-with-the-files
Closed

feat(board): the board art ships beside the files that name it#952
ExtraToast wants to merge 1 commit into
mainfrom
feat/board-art-ships-with-the-files

Conversation

@ExtraToast

@ExtraToast ExtraToast commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #949, which landed the board seed. Two things it left behind.

The board art ships beside the files that name it

db/seed/boards/art/ — the twenty-six board photographs and portraits the site draws, as WebP masters, with a CREDITS.md beside them. This mirrors db/seed/esports/art/, which is where the esports history keeps its own.

One rule locates a picture: the master for a row is that row's own image with .webp for an extension. A board whose image is board9/board9.jpg is drawn by art/board9/board9.webp; a seat whose image is board6/roos.jpg by art/board6/roos.webp. No lookup table, no second column, and nothing to fall out of step — which is why the directory structure is kept rather than flattened the way the esports art is.

Conversion, matching the esports pipeline: fitted so neither side exceeds 2560, aspect ratio untouched, nothing upscaled, then cwebp -q 82 -m 6. Nothing else changed.

The sixth board's portraits come from the *BIG.jpg copies sitting beside the ones the page loads — three to four times the resolution, 3803x5705 at the largest — so the masters are the best originals available rather than the thumbnails. Everything else was already at or under the cap and is untouched in size.

3.0 MB in total, against the 36 MB the frontend's asset directories hold. Those directories stay until #935; this is the groundwork for #929, which is what actually stores these on start-up. Nothing reads the directory yet.

Two tests keep it honest, both pure and both cheap:

  • every picture the files name ships beside them — resolved through the classloader, so it is the packaged resource that is checked. A row naming a master that is not there would be a board drawn blank on a fresh database, and nothing further down the stack would catch it.
  • the art directory holds nothing the files do not name — the other direction, because a picture nobody points at is megabytes nobody notices. Read off the source tree rather than the classpath: by the time a test runs the resources are inside a jar, and a jar is not a directory to walk.

CREDITS.md also records what is still wanted — a group photograph for boards 1 to 4, portraits for board 5, anything at all for the tenth board, and whether the two unreferenced images in the frontend's assets (wholeboardBIG.jpg, casual7thBoardPic.jpg) belong to a board.

The CodeQL warning on the seed

CodeQL flagged java/constant-comparison"Test is always false" — on if (attached > 0) in R__Boards_seed.migrate.

It was right about the shape, if not the outcome. attached, written and skipped were vars tallied inside a forEach, so Kotlin boxes each into a Ref.IntRef and the lambda writes to the field rather than the local. Read from the bytecode, attached is a local int initialised to 0 and never assigned in migrate at all — hence "always false". At runtime it worked; static analysis could not see that, and neither can a reader who has to hold the boxing in their head.

Fixed by counting from what came back instead of tallying as it goes:

val outcomes = seats.map { row -> … }
val attached = outcomes.count { it == Seat.ATTACHED }
val written = outcomes.count { it != Seat.LEFT_DELETED }

Same numbers, no mutable state crossing a lambda boundary, and the outcome of every seat is in one place. The when that dispatched on the three outcomes goes with it.

Tests

Run locally, exit codes checked. The integration suite ran against a throwaway MariaDB 10.11.10 container on port 3309 with blueshell-test created from services/api/0_init.sql and CI's own MYSQL_* env.

command result
./gradlew :services:api:compileKotlin :services:api:compileTestKotlin :services:api:compileIntegrationTestKotlin exit 0
./gradlew :services:api:test exit 0
./gradlew :services:api:integrationTest (full suite) exit 0

The frontend is untouched.


Diff breakdown added removed, scaled to the largest row.

api                                                +56    -13   28
  production         ███████░░░░░░░░               +12    -13   27
  unit tests         ██████████████████████████    +44     -0    1

──────────────────────────────────────────────────────────────────
production                                         +12    -13
tests                                              +44     -0  3.67 test lines per prod line
total (hand-written)                               +56    -13  28 files

@ExtraToast

Copy link
Copy Markdown
Contributor Author

Closing in favour of #955 and #954, which split this branch's two concerns.

The art duplicates #929, which was already in flight when this branch was built and is now open as #955. The two sets are 26 and 27 files with no overlapping paths — this branch nests them (art/board9/board9.webp), #955 flattens them (board9.webp, board6-amber.webp) — so merging both would ship two copies of every photograph under different names. #955 also carries what makes the art usable: the two new FileType kinds, ShippedBoardArt, the response shapes and a system test. Art without that wiring is inert.

The CodeQL fix is not lost. It is on #954 as its own commit, with an identical patch-id to this branch's, and nothing else attached to it. That keeps a one-line correctness fix from waiting on 3 MB of pictures to be reviewed.

Two things from this branch worth carrying, and both are recorded rather than discarded: the naming rule (a row's master is its own image value with .webp for an extension, so no lookup table can drift), and that board 6's portraits should come from the *BIG.jpg originals rather than the thumbnails. Both were relayed to #929 while it was still working.

No work is wasted that was not already being done twice — my fault for letting two agents reach the same files.

@ExtraToast ExtraToast closed this Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant