@feralfile/cli 2.10.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +31 -23
  2. package/config.json.example +6 -1
  3. package/dist/index.js +10 -2
  4. package/dist/package.json +5 -2
  5. package/dist/src/commands/build.js +40 -0
  6. package/dist/src/commands/config.js +1 -0
  7. package/dist/src/commands/device.js +85 -40
  8. package/dist/src/commands/enrich.js +18 -23
  9. package/dist/src/commands/find.js +144 -106
  10. package/dist/src/commands/helpers/device-control.js +937 -0
  11. package/dist/src/commands/helpers/hidden-alias-help.js +37 -0
  12. package/dist/src/commands/helpers/playlist-display.js +2 -15
  13. package/dist/src/commands/helpers/prompt.js +85 -10
  14. package/dist/src/commands/play.js +162 -84
  15. package/dist/src/commands/report.js +251 -0
  16. package/dist/src/commands/setup.js +82 -7
  17. package/dist/src/commands/status.js +4 -1
  18. package/dist/src/config.js +256 -6
  19. package/dist/src/main.js +14 -5
  20. package/dist/src/utilities/control/codec.js +578 -0
  21. package/dist/src/utilities/control/control-errors.js +157 -0
  22. package/dist/src/utilities/control/controller-store.js +964 -0
  23. package/dist/src/utilities/control/jwk.js +141 -0
  24. package/dist/src/utilities/control/pairing-channel.js +52 -0
  25. package/dist/src/utilities/control/pairing.js +416 -0
  26. package/dist/src/utilities/control/registration.js +391 -0
  27. package/dist/src/utilities/control/relay-pairing-channel.js +191 -0
  28. package/dist/src/utilities/control/secure-transport.js +850 -0
  29. package/dist/src/utilities/control/strict-json.js +376 -0
  30. package/dist/src/utilities/device-lookup.js +36 -11
  31. package/dist/src/utilities/device-network.js +129 -0
  32. package/dist/src/utilities/device-upsert.js +1 -1
  33. package/dist/src/utilities/feral-file-artwork.js +2 -2
  34. package/dist/src/utilities/ff1-compatibility.js +87 -11
  35. package/dist/src/utilities/ff1-device.js +161 -78
  36. package/dist/src/utilities/ff1-relayer.js +34 -14
  37. package/dist/src/utilities/handoff-client.js +23 -9
  38. package/dist/src/utilities/index.js +270 -259
  39. package/dist/src/utilities/media-url.js +117 -0
  40. package/dist/src/utilities/neort-marketplace.js +3 -3
  41. package/dist/src/utilities/nft-indexer.js +12 -376
  42. package/dist/src/utilities/playlist-builder.js +11 -2
  43. package/dist/src/utilities/playlist-cast.js +6 -6
  44. package/dist/src/utilities/playlist-source.js +223 -34
  45. package/dist/src/utilities/raster-client.js +101 -14
  46. package/dist/src/utilities/relay-client.js +774 -0
  47. package/dist/src/utilities/ssh-access.js +192 -58
  48. package/dist/src/utilities/support-report.js +511 -0
  49. package/dist/src/utilities/temporary-channel.js +139 -0
  50. package/dist/src/utilities/token-item.js +428 -0
  51. package/dist/src/utilities/token-source-contract.js +55 -0
  52. package/dist/src/utilities/token-source-indexer.js +99 -0
  53. package/dist/src/utilities/token-source-raster.js +378 -0
  54. package/dist/src/utilities/token-source.js +48 -0
  55. package/docs/CONFIGURATION.md +331 -28
  56. package/docs/EXAMPLES.md +33 -33
  57. package/docs/PROJECT_SPEC.md +55 -36
  58. package/docs/README.md +145 -43
  59. package/package.json +5 -2
package/docs/EXAMPLES.md CHANGED
@@ -18,7 +18,7 @@ npm run dev -- config validate
18
18
 
19
19
  ## Use with a coding agent
20
20
 
21
- ff-cli ships a [Claude Code](https://docs.claude.com/en/docs/claude-code) / Codex skill at `skills/ff-control/SKILL.md`. Once installed, ask your agent in plain language ("Get 3 works from reas.eth and play on Living Room", "Build a playlist from this Objkt URL and publish to my feed") and it translates the request into `ff-cli find` or `ff-cli build` and runs the validate → play/publish flow for you.
21
+ ff-cli ships a [Claude Code](https://docs.claude.com/en/docs/claude-code) / Codex skill at `skills/ff-control/SKILL.md`. Once installed, ask your agent in plain language ("Get 3 works from reas.eth and display on Living Room", "Build a playlist from this Objkt URL and publish to my feed") and it translates the request into `ff-cli find` or `ff-cli build` and runs the validate → display/publish flow for you.
22
22
 
23
23
  Recommended local install path:
24
24
 
@@ -32,19 +32,19 @@ The rest of this doc shows the deterministic commands the skill (or you) drives
32
32
 
33
33
  ## Find an artwork
34
34
 
35
- `ff-cli find` resolves a marketplace URL, raw `chain:contract:tokenId`, or wallet address into a playable DP-1 playlist. Sources: Art Blocks, Objkt, fxhash, OpenSea, SuperRare, Feral File, Neort, Verse, raw on-chain coordinates, and wallet addresses.
35
+ `ff-cli find` resolves a marketplace URL, raw `chain:contract:tokenId`, or wallet address into a DP-1 playlist ready to display. Sources: Art Blocks, Objkt, fxhash, OpenSea, SuperRare, Feral File, Neort, Verse, raw on-chain coordinates, and wallet addresses.
36
36
 
37
37
  ```bash
38
- # Paste a URL and play it on your FF1
39
- npm run dev -- find https://www.artblocks.io/collection/ringers-by-dmitri-cherniak --play
38
+ # Paste a URL and display it on your FF1
39
+ npm run dev -- find https://www.artblocks.io/collection/ringers-by-dmitri-cherniak --display
40
40
 
41
41
  # Tezos / hic et nunc via Objkt (the alias resolves to a KT1 contract)
42
- npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --play
42
+ npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --display
43
43
 
44
44
  # Feral File artwork (public id may be hex or numeric)
45
- npm run dev -- find https://feralfile.com/exhibitions/artwork/f0240e04d64717e319584957f6a83954b029254ad1260b6320472ea8c0c5b1cf --play
45
+ npm run dev -- find https://feralfile.com/exhibitions/artwork/f0240e04d64717e319584957f6a83954b029254ad1260b6320472ea8c0c5b1cf --display
46
46
 
47
- # Save without playing
47
+ # Save without displaying
48
48
  npm run dev -- find ethereum:0xababababab20053426ad1c782de9ea8444358070:5001410 -o send-receive.json
49
49
 
50
50
  # Single on-chain token by coordinates
@@ -62,11 +62,11 @@ npm run dev -- find https://www.artblocks.io/collection/ringers-by-dmitri-cherni
62
62
  # Build and publish to a configured feed server
63
63
  npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --publish
64
64
 
65
- # Build, play on a named device, and skip interactive prompts
66
- npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --play -d "Living Room Display" -y
65
+ # Build, display on a named device, and skip interactive prompts
66
+ npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --display -d "Living Room Display" -y
67
67
 
68
- # -y alone also plays (the scripted default); add --no-play to build and save without casting
69
- npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 -y --no-play
68
+ # -y alone also displays (the scripted default); add --no-display to build and save without casting
69
+ npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 -y --no-display
70
70
  ```
71
71
 
72
72
  OpenSea and Verse accept both item and collection/series URLs:
@@ -261,14 +261,14 @@ the flag; without it those items are skipped rather than guessed at, because
261
261
  the wrong network returns a different artwork's metadata. A Tezos playlist
262
262
  needs no flag.
263
263
 
264
- Items the indexer cannot resolve are listed rather than guessed at:
264
+ Items the token source cannot resolve are listed rather than guessed at:
265
265
 
266
266
  ```text
267
267
  Nothing to enrich
268
268
 
269
269
  Skipped 3:
270
270
  Kim Asendorf — PXL NET — no provenance.contract chain/address/tokenId to look up
271
- Untitled — the indexer returned nothing for it
271
+ Untitled — the token source returned nothing for it
272
272
  Pre-Process — chain "evm" names a family; pass --assume-ethereum to assert the network
273
273
  ```
274
274
 
@@ -278,14 +278,14 @@ has to be re-signed:
278
278
  ```bash
279
279
  ff-cli enrich playlist.json --assume-ethereum
280
280
  ff-cli sign playlist.json
281
- ff-cli play playlist.json -d "living room"
281
+ ff-cli display playlist.json -d "living room"
282
282
  ```
283
283
 
284
284
  Casting does not care about the signing role. Add `-r curator` to that `sign` if the playlist is also
285
285
  going to a feed: `ff-cli publish` requires the owner role, for the reasons in
286
286
  [Publish to Feed Server](#publish-to-feed-server).
287
287
 
288
- ## Validate / Sign / Play
288
+ ## Validate / Sign / Display
289
289
 
290
290
  ```bash
291
291
  # Validate playlist structure
@@ -298,27 +298,27 @@ npm run dev -- verify playlist.json
298
298
  # Sign playlist (uses key/role from config, or override via --key / --role)
299
299
  npm run dev -- sign playlist.json -o signed.json
300
300
 
301
- # Play on the configured default device
302
- npm run dev -- play playlist.json
301
+ # Display on the configured default device
302
+ npm run dev -- display playlist.json
303
303
 
304
- # Play on a specific named device
305
- npm run dev -- play signed.json -d "Living Room Display"
304
+ # Display on a specific named device
305
+ npm run dev -- display signed.json -d "Living Room Display"
306
306
 
307
- # Play a hosted DP-1 playlist
308
- npm run dev -- play "https://cdn.example.com/playlist.json"
307
+ # Display a hosted DP-1 playlist
308
+ npm run dev -- display "https://cdn.example.com/playlist.json"
309
309
 
310
- # Play a playlist straight from a DP-1 feed server (the URL the feed hands out)
310
+ # Display a playlist straight from a DP-1 feed server (the URL the feed hands out)
311
311
  # Wallet-signed (eip191) documents need --skip-verify until #103 lands
312
- npm run dev -- play "https://feed.feralfile.com/api/v1/playlists/<slug>" --skip-verify
312
+ npm run dev -- display "https://feed.feralfile.com/api/v1/playlists/<slug>" --skip-verify
313
313
 
314
- # Play a media URL directly
315
- npm run dev -- play "https://example.com/video.mp4"
314
+ # Display a media URL directly
315
+ npm run dev -- display "https://example.com/video.mp4"
316
316
 
317
317
  # Skip verification only if you must send a non-conformant payload (not recommended)
318
- npm run dev -- play playlist.json --skip-verify
318
+ npm run dev -- display playlist.json --skip-verify
319
319
  ```
320
320
 
321
- > **No feed server is required to cast.** A device can play any static, signed DP-1 playlist hosted at a public URL — sign it (`sign`), upload the JSON anywhere that serves it over HTTPS (S3, Supabase Storage, a static host, etc.), then `ff-cli play "<url>"`. The DP-1 Feed server ([Publish to Feed Server](#publish-to-feed-server) below) adds discovery and curation, but is optional for simply playing your own playlists.
321
+ > **No feed server is required to cast.** A device can display any static, signed DP-1 playlist hosted at a public URL — sign it (`sign`), upload the JSON anywhere that serves it over HTTPS (S3, Supabase Storage, a static host, etc.), then `ff-cli display "<url>"`. The DP-1 Feed server ([Publish to Feed Server](#publish-to-feed-server) below) adds discovery and curation, but is optional for simply displaying your own playlists.
322
322
 
323
323
  ## Publish to Feed Server
324
324
 
@@ -921,7 +921,7 @@ says so rather than sending you after a key that does not exist. That is the sta
921
921
  published without an owner-role signature is frozen in, and it is what the `publish` owner-role gate
922
922
  above exists to prevent.
923
923
 
924
- ## Complete Flow (build → validate → sign → play → publish)
924
+ ## Complete Flow (build → validate → sign → display → publish)
925
925
 
926
926
  ```bash
927
927
  # 1. Build a playlist (via find or build)
@@ -937,8 +937,8 @@ npm run dev -- validate playlist.json
937
937
  # what feeds enforce today.
938
938
  npm run dev -- sign playlist.json -r curator -o signed.json
939
939
 
940
- # 4. Play it on a device
941
- npm run dev -- play signed.json -d "Living Room Display"
940
+ # 4. Display it on a device
941
+ npm run dev -- display signed.json -d "Living Room Display"
942
942
 
943
943
  # 5. Publish to a feed server
944
944
  npm run dev -- publish signed.json -s 0
@@ -949,17 +949,17 @@ key declared in `curators[]`. Skip step 3 and use `playlist.json` in steps 4 and
949
949
  `signed.json` on that path:
950
950
 
951
951
  ```bash
952
- npm run dev -- play playlist.json -d "Living Room Display"
952
+ npm run dev -- display playlist.json -d "Living Room Display"
953
953
  npm run dev -- publish playlist.json -s 0
954
954
  ```
955
955
 
956
956
  Set `playlist.curatorName` in the config to control the name recorded in `curators[]`; it defaults
957
957
  to `ff-cli`.
958
958
 
959
- `ff-cli find` can collapse build + play + publish into one command:
959
+ `ff-cli find` can collapse build + display + publish into one command:
960
960
 
961
961
  ```bash
962
- npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --play -d "Living Room Display" --publish
962
+ npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --display -d "Living Room Display" --publish
963
963
  ```
964
964
 
965
965
  ## FF1 device management
@@ -15,7 +15,7 @@ It is derived from the behavior and interfaces implemented in this repository as
15
15
  - Project: `ff-cli`
16
16
  - Type: Node.js CLI
17
17
  - System role: a control and integration surface for FF1 and DP-1 workflows
18
- - Primary purpose: turn resolved sources or structured parameters into valid DP-1 playlists deterministically, then validate them and optionally sign, publish, and play them through FF1 and feed paths
18
+ - Primary purpose: turn resolved sources or structured parameters into valid DP-1 playlists deterministically, then validate them and optionally sign, publish, and display them through FF1 and feed paths
19
19
 
20
20
  There is no built-in natural-language interface and no model orchestration. Natural language belongs in the user's coding agent (Claude Code, Codex), which drives ff-cli's deterministic commands via the `ff-control` skill. ff-cli requires no LLM API key.
21
21
 
@@ -25,11 +25,11 @@ In the Feral File architecture bands, `ff-cli` sits primarily in the presentatio
25
25
 
26
26
  The CLI supports the broader Feral File goal of making it effortless to live with digital art every day.
27
27
 
28
- Its value is reducing friction in the publish-to-play path:
28
+ Its value is reducing friction in the publish-to-display path:
29
29
 
30
30
  - assemble playlists quickly
31
31
  - keep outputs DP-1 conformant
32
- - make FF1 playback and feed publishing easier to exercise
32
+ - make displaying on FF1 and feed publishing easier to exercise
33
33
  - provide deterministic tooling that agents and scripts can drive reliably
34
34
 
35
35
  The CLI should strengthen the Gold Path, not invent a parallel product model.
@@ -39,7 +39,7 @@ The CLI should strengthen the Gold Path, not invent a parallel product model.
39
39
  Current likely users:
40
40
 
41
41
  - internal engineers working on FF1, DP-1, feed, and device flows
42
- - operators and launch teammates validating publish-to-play behavior
42
+ - operators and launch teammates validating publish-to-display behavior
43
43
  - advanced users or partners building and testing playlists
44
44
  - developers using the CLI as a reference implementation for DP-1 and FF1 command flows
45
45
 
@@ -50,7 +50,7 @@ Primary use cases:
50
50
  - validate or verify a local or hosted DP-1 playlist
51
51
  - sign a playlist with an Ed25519 key
52
52
  - publish a validated playlist to a configured feed server
53
- - play a playlist or direct media URL on a configured FF1 device
53
+ - display a playlist or direct media URL on a configured FF1 device
54
54
  - manage local config and FF1 SSH access
55
55
  - exercise compatibility checks against FF1 OS versions before risky commands
56
56
 
@@ -73,15 +73,15 @@ Use these terms consistently:
73
73
 
74
74
  The current code and internal context imply these practical goals:
75
75
 
76
- - Make playlist creation and playback testing fast enough for daily use.
76
+ - Make playlist creation and display testing fast enough for daily use.
77
77
  - Keep the path from intent to valid DP-1 output deterministic and inspectable.
78
78
  - Preserve openness by relying on DP-1 as the compatibility layer instead of a CLI-specific format.
79
- - Support FF1 as the reference playback target without making correctness depend on proprietary-only infrastructure.
80
- - Serve as a reference surface for publish, verify, and play flows used elsewhere in the Feral File stack.
79
+ - Support FF1 as the reference display target without making correctness depend on proprietary-only infrastructure.
80
+ - Serve as a reference surface for publish, verify, and display flows used elsewhere in the Feral File stack.
81
81
 
82
82
  ### Current behavior
83
83
 
84
- The current implementation still depends on Feral File-operated infrastructure for some data retrieval paths, including the hardcoded production indexer endpoint used for NFT lookup.
84
+ Token data for `find`, `build`, and `enrich` comes from the Feral File indexer (ff-indexer-v2) by default. Raster's public GraphQL API is selectable with `tokenSource: "raster"` and is under evaluation as the replacement (feral-file#3576); it stays opt-in until the data bugs reported on feral-file#3546 are fixed. One token source answers a whole run; there is no fallback between them.
85
85
 
86
86
  ### Design direction
87
87
 
@@ -103,16 +103,22 @@ Based on the code today, the CLI is responsible for:
103
103
 
104
104
  - loading configuration from `config.json`, `.env`, and defaults, with `config.json` taking precedence
105
105
  - resolving marketplace URLs, on-chain coordinates, and wallet addresses into playlists (`find`)
106
- - running feed fetches, address queries, contract-based NFT queries, domain resolution, playlist building, verification, publishing, and playback
106
+ - running feed fetches, address queries, contract-based NFT queries, domain resolution, playlist building, verification, publishing, and display
107
107
  - supporting a deterministic build path from structured JSON (`build`)
108
- - building DP-1 playlist envelopes from NFT metadata or direct media URLs via `dp1-js` document and leaf builders (so constructed playlists stay schema-conformant), including inline Ref Manifests on items that carry indexer metadata
108
+ - building DP-1 playlist envelopes from NFT metadata or direct media URLs via `dp1-js` document and leaf builders (so constructed playlists stay schema-conformant), including inline Ref Manifests on items that carry token-source metadata
109
109
  - validating and verifying playlist structure and signatures
110
110
  - signing playlists when a private key is configured
111
111
  - publishing validated playlists to configured feed servers
112
- - discovering configured FF1 devices and sending playlists or direct media playback requests
113
- - pairing a device's signed relayer topic through a short-lived end-to-end
114
- encrypted mobile handoff, authenticating the CLI key with a user-compared
115
- security check, and storing it in the operating system credential vault
112
+ - discovering configured FF1 devices and sending playlists or direct media display requests
113
+ - pairing as an FF1 controller through owner-initiated registration: the CLI
114
+ shows a QR of its public keys and a one-time secret, an owner adds it in the
115
+ Feral File app, and the CLI pins the FF1 profile only from the owner's sealed
116
+ answer over the relay pairing channel, then enrolls (any relayer topic the
117
+ answer carries goes to the operating system credential vault)
118
+ - pairing an FF1 without secure control by its signed relayer topic through
119
+ a short-lived end-to-end encrypted mobile handoff, authenticating the CLI key
120
+ with a user-compared security check, and storing it in the operating system
121
+ credential vault
116
122
  - falling back from unreachable LAN delivery to the shared FF1 relayer with an
117
123
  explicit terminal notice, so sandboxed and cross-subnet control remains
118
124
  observable to the mobile app
@@ -159,13 +165,17 @@ Today the CLI groups into these workflow areas:
159
165
  - `find`
160
166
  - `build`
161
167
 
162
- An item's `provenance.contract` is read from the indexer row, not inferred. Each
163
- row carries the token's own `standard` (`erc721`, `erc1155`, `fa2`) and its
164
- CAIP-2 `chain` (`eip155:1`, `tezos:mainnet`), and both are written through. The
165
- client's own detection sees a chain name and an address and nothing else, so it
166
- answers `erc721` for every EVM contract; it applies only to rows that carry no
167
- standard, and to the CID a lookup by coordinate must build before the indexer
168
- has been asked anything. A row naming a chain DP-1 has no word for is recorded
168
+ An item's `provenance.contract` is read from the token source's row, not
169
+ inferred. Each row carries the token's own standard and its CAIP-2 `chain`
170
+ (`eip155:1`, `tezos:NetXdQprcVkpaWU` on Raster, `tezos:mainnet` on the
171
+ indexer), and both are written through. Raster standards DP-1 cannot name
172
+ (`CRYPTOPUNKS`, `ORDINAL_INSCRIPTION`) are written as `other`. Raster
173
+ lowercases EVM addresses; they are checksummed before use, so an item's `id`
174
+ (derived from the address and token id) and its provenance are the same
175
+ whichever source built it. The client's own detection sees a chain name and an
176
+ address and nothing else, so it answers `erc721` for every EVM contract; it
177
+ applies only to rows that carry no standard, and to the CID a lookup by
178
+ coordinate must build before the indexer has been asked anything. A row naming a chain DP-1 has no word for is recorded
169
179
  as `other` — the item is still built, and the client's guess is never
170
180
  substituted for a chain the row already named.
171
181
 
@@ -177,7 +187,7 @@ substituted for a chain the row already named.
177
187
 
178
188
  ### Delivery
179
189
 
180
- - `play` (handles playlist files, playlist URLs, and media URLs)
190
+ - `display` (handles playlist files, playlist URLs, and media URLs; `play` is a hidden alias kept for existing scripts and agents)
181
191
  - `fetch`
182
192
  - `publish` (`--replace` sends an owner-bound replacement instead of a create)
183
193
  - `unpublish`
@@ -248,6 +258,13 @@ replacement.
248
258
 
249
259
  - `ssh enable|disable`
250
260
 
261
+ ### Support
262
+
263
+ - `report` (posts a problem report to Feral File's support-logs, which mints the `Support [<id>]`
264
+ reference and a token scoped to that one report; with `-d`, the Art Computer is then asked to upload
265
+ its logs under the same reference with its existing `uploadLogs` command. ff-cli holds no support
266
+ credential, since a key in a public package is public)
267
+
251
268
  ### Inline Ref Manifests
252
269
 
253
270
  Playlist items carry a full Ref Manifest inline (DP-1 Playlist Extension §3.6)
@@ -284,13 +301,13 @@ and nothing else. `enrich` is the repair path for those.
284
301
  - It writes `inlineManifest` and nothing else. `source`, `duration`, `title`,
285
302
  `id`, and `display` are curator decisions and survive untouched even when the
286
303
  indexer disagrees with them.
287
- - An item the indexer cannot resolve is reported, never synthesized. The same
304
+ - An item the token source cannot resolve is reported, never synthesized. The same
288
305
  rule the manifest mapping follows applies here: the CLI does not invent fields
289
306
  it cannot substantiate, and an invented artist line inside a signed document
290
307
  is worse than an absent one.
291
- - DP-1 names the EVM family `evm`; the FF indexer names it `ethereum`. Enrich
292
- translates between the two. Unlisted chain names pass through so the indexer
293
- decides what it supports.
308
+ - DP-1 names the EVM family `evm`; the token sources name it `ethereum`. Enrich
309
+ translates between the two. Unlisted chain names pass through so the token
310
+ source decides what it supports.
294
311
  - Enrichment changes the document, so both the `signatures[]` envelope and the
295
312
  legacy flat `signature` are removed and the playlist must be re-signed.
296
313
  Leaving a stale envelope in place would produce a file that fails
@@ -302,9 +319,10 @@ and nothing else. `enrich` is the repair path for those.
302
319
  discards the integrity hash the remote manifest is checked against. That
303
320
  conversion, if ever wanted, belongs behind its own flag.
304
321
  - Enrichment looks each distinct coordinate up once, however many items share
305
- it. A token the indexer has not seen triggers an indexing job and a poll that
306
- can take minutes, and a playlist that repeats a work would otherwise submit
307
- that job once per appearance.
322
+ it. On Raster the lookups are batched; on the indexer a token it
323
+ has not seen triggers an indexing job and a poll that can take minutes, and a
324
+ playlist that repeats a work would otherwise submit that job once per
325
+ appearance.
308
326
  - Overriding an item's title changes the manifest's content, so it also changes
309
327
  the manifest's `id`. The indexer derives that id from the token coordinate,
310
328
  so two items of one artwork receive the same one; leaving it alone while
@@ -352,7 +370,8 @@ and nothing else. `enrich` is the repair path for those.
352
370
  nor the response can say which network is meant. Ethereum is chosen because
353
371
  it is the only EVM network this client can reach — `buildTokenCID` maps
354
372
  ethereum to `eip155:1` and tezos to `tezos:mainnet` and throws for anything
355
- else. The residual risk is narrow: an L2 work whose address and token id also
373
+ else, and the Raster token source likewise builds Ethereum and Tezos mainnet
374
+ only. The residual risk is narrow: an L2 work whose address and token id also
356
375
  exist on Ethereum would take the Ethereum work's metadata. The command
357
376
  is the operator's to make: `--assume-ethereum` asserts it, and without that
358
377
  flag `evm` items are skipped with a reason that names the flag. The warning
@@ -411,7 +430,7 @@ and nothing else. `enrich` is the repair path for those.
411
430
  - The playlist is validated before lookup and the enriched candidate is
412
431
  validated before writing. On either failure the diagnostics are printed and
413
432
  the file is left untouched, rather than replaced with a document that sign,
414
- publish, and play would each reject later.
433
+ publish, and display would each reject later.
415
434
 
416
435
  ## Deterministic-first behavior
417
436
 
@@ -488,16 +507,16 @@ Important constraints from the broader FF system:
488
507
  ### Current behavior
489
508
 
490
509
  - reliability matters more than novelty
491
- - the publish-to-play path should stay simple and testable
492
- - the CLI should help prove the path from canonical JSON to FF1 playback
510
+ - the publish-to-display path should stay simple and testable
511
+ - the CLI should help prove the path from canonical JSON to FF1 display
493
512
  - compatibility checks fail clearly when incompatibility is confirmed
494
513
  - if FF1 OS version cannot be determined during preflight, the CLI currently proceeds and logs a warning instead of hard-blocking the command
495
514
 
496
515
  ### Design direction
497
516
 
498
517
  - reliability matters more than novelty
499
- - the publish-to-play path should stay simple and testable
500
- - the CLI should help prove the path from canonical JSON to FF1 playback
518
+ - the publish-to-display path should stay simple and testable
519
+ - the CLI should help prove the path from canonical JSON to FF1 display
501
520
  - compatibility messaging should remain explicit enough that operators can distinguish confirmed incompatibility from uncertain device state
502
521
 
503
522
  ## Code and design constraints