File size: 15,434 Bytes
a290b8b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
644ba85
 
a290b8b
 
 
644ba85
 
a290b8b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# Data loading and caching

This document describes the current implementation of data loading and caching in the
HiveTrace Guardrail Leaderboard frontend.

The implementation has three goals:

- keep the private Hugging Face token on the SvelteKit server;
- avoid downloading and adapting unchanged bucket payloads;
- make repeated client-side navigation fast while providing a predictable data freshness window.

## Architecture

```text
Browser
  -> SvelteKit page or __data.json request
  -> Hugging Face Space Node process
  -> private Hugging Face bucket
       -> latest/manifest.json
       -> payload files referenced by the manifest
```

The browser never reads the private bucket directly. All bucket requests are made by the
SvelteKit server with the server-only `HF_TOKEN` environment variable.

## Data source

The bucket is configured with these runtime variables:

```text
HF_TOKEN=<private read token>
HF_BUCKET_ID=hivetrace/leaderboard_frontend_v2
HF_BUCKET_PREFIX=latest
HF_BUCKET_REQUEST_TIMEOUT_MS=60000
HF_BUCKET_REQUEST_RETRIES=2
HF_BUCKET_ENDPOINT=https://huggingface.co
```

`HF_BUCKET_ENDPOINT`, `HF_BUCKET_REQUEST_TIMEOUT_MS`, and `HF_BUCKET_REQUEST_RETRIES` are optional.
The values above are their defaults.

`HF_BUCKET_CACHE_TTL_MS` still controls the regular in-memory manifest cache and the direct
Tools snapshot helper. The main Ranking, Details, and Visualizations page-data flow explicitly
refreshes the manifest after the browser cache misses, so this variable does not add another
freshness delay to normal client-side page transitions.

## Manifest as the version pointer

`latest/manifest.json` is the single version pointer used by the frontend. Its important fields
are:

- `snapshot_id`: the identity of the published dataset;
- `files`: paths to all payload files;
- `hashes`: SHA-256 hashes of the payload files;
- `schema_version`: the bucket contract version;
- model, group, and dataset counts used for validation.

The frontend decides whether payload data changed by comparing `snapshot_id`. A new publish
must always use a new, unique `snapshot_id`.

Changing payload files or hashes without changing `snapshot_id` is not supported. In that case,
the frontend considers the snapshot unchanged and can continue using the old in-memory payload
until the Space process restarts.

## Routes and payloads

| Route          | Server loader               | Bucket data                                                                                                       |
| -------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `/`            | `getHfBucketRankingState()` | catalog, leaderboard, and details matrix                                                                          |
| `/details`     | `getHfBucketDetailsState()` | catalog, leaderboard, and details matrix                                                                          |
| `/tools`       | `getHfBucketToolsState()`   | catalog, leaderboard, drilldown index, radar, scatter, heatmap, grouped bars, Pareto, performance, and robustness |
| `/methodology` | no bucket page loader       | no bucket payload                                                                                                 |

Ranking also uses the details matrix because the `partial` model status is derived from
`metrics_evaluated_samples < sample_count`.

The root `+layout.server.ts` reads the manifest separately to expose public bucket status such
as snapshot date and model count. That status uses the regular manifest cache. It is metadata
for the layout and does not control page-data freshness.

## Client-side navigation

SvelteKit intercepts internal menu links and requests route data through endpoints such as:

```text
/__data.json
/details/__data.json
/tools/__data.json
```

Localized variants are recognized as well, for example `/ru/details/__data.json`.

The response optimization in `src/hooks.server.ts` applies only to these three page-data
routes. It does not apply to Methodology, static assets, errors, or arbitrary API responses.

### Browser cache

Successful page-data responses use:

```http
Cache-Control: private, max-age=300
```

This means:

- each browser can reuse a route response for five minutes;
- the response is not a public CDN or shared-proxy cache entry;
- no `stale-while-revalidate` window is used;
- after five minutes, the next navigation must contact the SvelteKit server before rendering
  that route.

The cache is per response URL, including SvelteKit query parameters. Ranking, Details, and
Visualizations therefore have independent browser cache entries.

An already rendered page does not update itself. Fresh data is applied on a later navigation or
full page reload.

### Gzip compression

The same hook compresses a page-data response when all conditions are true:

- the response is successful and has a body;
- its declared size is at least 1,024 bytes;
- the client accepts `gzip`.

The compressed response contains:

```http
Content-Encoding: gzip
Vary: Accept-Encoding
```

`Content-Length` is removed because the compressed body is streamed. Clients without gzip
support receive the original body with the same five-minute private cache policy.

Approximate measured sizes for the current dataset are:

| Route data     | Uncompressed |   Gzip |
| -------------- | -----------: | -----: |
| Ranking        |       171 KB |  58 KB |
| Details        |       643 KB | 158 KB |
| Visualizations |       709 KB | 122 KB |

These sizes depend on the bucket contents and will change as models and datasets are added.

## Server request flow

When the browser does not have a fresh page-data response, the server follows this flow:

1. The page loader calls the corresponding Ranking, Details, or Tools state function.
2. The state function calls `fetchBucketRankingSnapshot({ refreshManifest: true })`.
3. `refreshManifest: true` bypasses the regular manifest TTL and reads the current small
   `manifest.json` from Hugging Face.
4. If the returned `snapshot_id` matches the in-memory ranking snapshot, catalog and leaderboard
   are reused without another payload download.
5. If `snapshot_id` changed, catalog and leaderboard are downloaded in parallel, their hashes
   and schemas are validated, and the ranking snapshot is replaced.
6. Route-specific data is reused or rebuilt for the same new `snapshot_id`.
7. SvelteKit serializes the adapted route data, and the server hook applies the private cache
   header and gzip compression.

The important distinction between the snapshot options is:

- `refreshManifest: true` always checks the manifest but reuses payloads when `snapshot_id` is
  unchanged;
- `forceRefresh: true` also bypasses payload reuse and rebuilds the ranking snapshot.

Normal page transitions use `refreshManifest`, not `forceRefresh`.

## In-memory caches

All server caches are module-level memory in the running Node process. They are private to a
single Space replica and are cleared when the container restarts, sleeps, or is redeployed.

### Manifest cache

`src/lib/server/hf-bucket/cache.ts` stores:

- the parsed manifest;
- the time it was fetched;
- its expiration time;
- one shared in-flight manifest request.

Regular callers use `HF_BUCKET_CACHE_TTL_MS`, with a five-minute default. Page-data refreshes use
the forced manifest path described above. Concurrent forced checks join the same in-flight
request when they overlap.

### Ranking snapshot

The ranking snapshot contains the manifest, catalog, and leaderboard. It is cached by
`snapshot_id`.

Concurrent downloads of the same snapshot share one promise. In-flight requests are also keyed
by `snapshot_id`, so a request for a newly published snapshot does not accidentally reuse a
download for an older snapshot.

### Details snapshot

The details snapshot adds `details_matrix` to the ranking snapshot and is cached by
`snapshot_id`.

This cache is shared by Ranking and Details. Ranking needs the matrix for `partial` detection, so
opening Details after Ranking does not download and validate `details_matrix` a second time.
Concurrent requests for the same details snapshot also share one promise.

### Adapted Ranking and Details datasets

The UI-ready Ranking and Details objects are cached by `snapshot_id`. When the manifest is
unchanged, the server returns the already adapted object. A new snapshot is parsed, validated,
and adapted once per Node process.

### Visualizations snapshot and adapted Tools dataset

For a new snapshot, the visualization files are downloaded in parallel. The raw visualization
snapshot and the adapted Tools dataset are cached separately by `snapshot_id`.

The direct `getHfBucketToolsSnapshot()` helper retains its TTL-based fast path. The `/tools`
page uses the state path, which refreshes the manifest after a browser cache miss.

## Validation

Payload reuse is allowed only after the manifest version check. New payloads go through:

- JSON parsing;
- schema parsing;
- SHA-256 verification when a hash is present;
- manifest count checks;
- model, group, and dataset reference checks;
- matrix completeness and duplicate-pair checks;
- visualization reference checks.

A validation error is handled in the same way as another refresh failure.

## Data freshness guarantee

Assume a valid new snapshot is published at time `T` and the bucket remains reachable.

### Route response is already in the browser cache

The old route response can be used until its individual five-minute `max-age` expires. The first
navigation to that route after expiration reads the fresh manifest. If `snapshot_id` changed,
the same navigation waits for and receives the new payload.

Therefore, the expected guarantee is:

> No later than the first navigation after the route's five-minute browser cache expires, the
> user receives the new snapshot.

There is no additional stale response window.

### Route response is not in the browser cache

The navigation immediately contacts the server and checks the manifest. If the server already
has the new payload, it reuses it. Otherwise, the navigation waits while the new snapshot is
downloaded and adapted.

### Full page reload

The five-minute policy targets SvelteKit `__data.json` navigation responses. A normal full HTML
request is not covered by this page-data cache and runs the server page loader again.

### Exceptions

The five-minute expectation does not apply when:

- Hugging Face or the network is unavailable;
- the new payload fails parsing, hash checks, or validation;
- the publisher reused the old `snapshot_id`;
- the manifest was published before all referenced files became readable.

## Failure behavior

The cache is also a resilience mechanism:

- if a refresh fails and a usable route dataset exists, the server returns cached data;
- if a new manifest is readable but a new payload is invalid or unavailable, the route state is
  returned as `stale` and the UI can show a warning;
- if no usable cache exists, the route returns an `unavailable` state with an empty fallback
  dataset;
- simultaneous requests share in-flight work to avoid duplicate bucket downloads.

One implementation detail is worth noting: when a forced manifest read fails but an older
manifest is cached, the manifest layer can return that stale manifest. The existing route data
can then continue to be served. The current route state does not always propagate this specific
manifest fallback as a visible `stale` warning.

## Publishing a new snapshot

The producer must publish atomically from the frontend's point of view:

1. Generate all payload files.
2. Use immutable or snapshot-specific file paths where practical.
3. Calculate and write the SHA-256 hashes.
4. Upload every payload file and verify it is readable.
5. Create a manifest with a new unique `snapshot_id`, correct paths, hashes, counts, and schema
   version.
6. Upload `latest/manifest.json` last.

Publishing the manifest last prevents the frontend from seeing a new version that references
files which are not available yet.

## Cold starts and replicas

After a Space restart or cold start, no in-memory snapshot exists. The first request must read
the manifest and all payloads required by that route. Later requests reuse the prepared data.

If the Space runs multiple replicas, each replica has its own memory cache and warms
independently. The browser cache remains local to each user.

## Operational checks

To inspect the page-data response headers, use an authenticated request to the Space:

```bash
curl -sS \
  -H "Authorization: Bearer $HF_TOKEN" \
  -H "Accept-Encoding: gzip" \
  -D - \
  -o /dev/null \
  "https://<space-domain>/details/__data.json"
```

Expected headers include:

```http
Cache-Control: private, max-age=300
Content-Encoding: gzip
Vary: Accept-Encoding
```

`curl` does not reproduce the browser's navigation cache unless an explicit curl cache is used.
Repeated curl requests therefore reach the server and can trigger repeated manifest checks.

When verifying a publish, check all of the following:

- the manifest has a new `snapshot_id`;
- every referenced file exists;
- hashes match the published contents;
- the Space logs contain no bucket validation errors;
- the first route navigation after browser cache expiration shows the new snapshot.

## Implementation map

| Responsibility                               | File                                                                                                   |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| HTTP bucket client and server-only token     | `src/lib/server/hf-bucket/client.ts`                                                                   |
| Regular manifest cache and in-flight request | `src/lib/server/hf-bucket/cache.ts`                                                                    |
| Ranking snapshot download and validation     | `src/lib/server/hf-bucket/ranking-snapshot.ts`                                                         |
| Shared details snapshot                      | `src/lib/server/hf-bucket/details-snapshot.ts`                                                         |
| Visualization snapshot download              | `src/lib/server/hf-bucket/tools-snapshot.ts`                                                           |
| Adapted Ranking cache                        | `src/lib/server/hf-bucket/ranking-cache.ts`                                                            |
| Adapted Details cache                        | `src/lib/server/hf-bucket/details-cache.ts`                                                            |
| Raw and adapted Tools caches                 | `src/lib/server/hf-bucket/tools-cache.ts`                                                              |
| Browser cache headers and gzip               | `src/hooks.server.ts`                                                                                  |
| Root public bucket status                    | `src/routes/+layout.server.ts`                                                                         |
| Route orchestration                          | `src/routes/+page.server.ts`, `src/routes/details/+page.server.ts`, `src/routes/tools/+page.server.ts` |