Skip to content

investigate: storage-target descriptors and misconfiguration diagnostics for .lnk / assets.json #1356

Description

@zackees

Summary

A .lnk today describes where an asset comes from, never where it should end up. There is no notion of a storage target (LittleFS, SPIFFS, SD card, embedded-in-firmware, WASM VFS), so a build cannot tell a correctly-configured project from a broken one — and says nothing either way.

This issue is to investigate the design, not to lock one in. The shape below is a starting point; the corner cases are the real content.

Verified current behavior

fbuild lnk add writes:

{ "sha256": "164804d9…", "size": 6051840, "url": "https://…", "v": 1 }

No destination field. And fbuild lnk pull resolves into the global cache only — nothing is materialized beside the .lnk:

lnk pull: 1 ok, 0 failed (of 1)
  → ~/.fbuild/prod/cache/archives/lnk-blobs/raw-video1.rgb/…/<sha256>/video1.rgb

$ ls examples/Fx/FxLedmapper32x32/data/
.gitignore  readme.txt  screenmap.json  video1.rgb.lnk     # <- no video1.rgb

So the bytes are fetched and verified, then stop. Nothing consumes them.

Related context: FastLED has no LittleFS backend at allFsImpl is implemented only for Arduino SD (SPI), the WASM browser VFS, and a host stub. And fbuild has no buildfs/uploadfs. See #1354.

The gap

data/*.lnk → [lnk pull ✅] → global cache → ??? → device filesystem
                                            ▲
                                   no destination concept

Direction to investigate

1. A destination on the descriptor

Something like a dest block naming the storage target:

{
  "sha256": "164804d9…",
  "size": 6051840,
  "url": "https://…",
  "dest": { "target": "littlefs", "path": "/video1.rgb" },
  "v": 2
}

Candidate targets: littlefs, spiffs, sdcard, firmware (baked as a byte array), vfs (WASM preview), none (host/test only).

assets.json would carry the same vocabulary, plus a file-level default so many assets can share one target without repeating it:

{
  "defaults": { "target": "littlefs" },
  "assets": { "video1.rgb": { "url": "", "sha256": "" } }
}

Version bump required. Adding dest to a v1 .lnk changes its meaning, so this is v: 2. A v1 .lnk must keep working — which forces the "no destination declared" question below.

2. Diagnostics — the actual ask

Every declaration should produce a clear verdict. A proposed severity split:

Error (fails the build)

  • sha256 mismatch — already the rule; never silently accept
  • asset exceeds the filesystem partition
  • target unsupported on the selected board (e.g. littlefs on AVR)
  • littlefs target with no filesystem partition in the partition table
  • two declarations naming the same file with conflicting targets

Warning (yellow)

  • .lnk with no destination descriptor — the case that prompted this issue. Fetches and caches, but goes nowhere. Should say so and name the default it fell back to.
  • sdcard target — fbuild cannot write to a card it does not have; the copy is manual and the warning must say that plainly
  • a large file in data/ with no .lnk (committed binary that arguably should be remote)
  • .lnk missing sha256 — fetch works, integrity does not

Info

  • cache hit vs fetched, and the resolved target per asset

Warnings must name the offending file and the concrete fix. A yellow line reading "no destination" is only useful if it also says what to add.

Corner cases to work through

These are the reason this needs investigation rather than a patch:

  1. No destination declared — hard error, or warn-and-default? A default of littlefs breaks SD-based sketches like FxLedmapper32x32; a default of sdcard silently does nothing at build time. Neither is obviously right, and v1 .lnk compatibility forces an answer.
  2. .lnk sidecars must be excluded from any generated image — shipping video1.rgb.lnk to the device is always wrong.
  3. Plain files in data/ with no .lnk — do they join the image implicitly? Mixed remote and committed assets in one directory is the common case.
  4. Partition sizing — total data/ versus partition capacity must fail at build time, never at runtime mount.
  5. Platform capability matrix — LittleFS support differs across ESP32 / ESP8266 / RP2040 / Teensy / AVR. Needs a real table, not assumptions.
  6. SD card is not deployable by a build tool. Is it a target at all, or just documentation?
  7. Conflicting declarations.lnk currently overrides assets.json for the same filename (FastLED's ci/asset_resolver.py rule). Should a target conflict silently follow that precedence, or error?
  8. WASM preview ignores targets entirely — everything is browser VFS. Should a littlefs target warn under a WASM build, or be silently ignored?
  9. Filename constraints — LittleFS filename length and path-depth limits can reject names that were fine on disk.
  10. Offline builds — cache miss plus no network needs a distinct, actionable message, not a generic fetch failure.
  11. Shared assets across sketches with different targets — is the target a property of the asset or of the sketch that uses it?
  12. Firmware-embedded target — bakes into the binary and interacts with bloat/size budgets rather than a filesystem.

Open questions

  • Does target belong on the asset, on the sketch, or on the board environment? An asset reused by two sketches may need different answers.
  • Should lnk pull gain a --materialize mode that writes beside the .lnk, or does only buildfs consume the cache?
  • Is assets.json the right home for defaults, or should that live in platformio.ini / the environment?

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions