Notes from the build · 0128 August 2026 · 6 minutes

Why the scan never leaves your bucket

Most labelling tools ask you to upload the scans first. Nitsor reads them where they already are, a few hundred kilobytes at a time. Here is the arithmetic, what we keep instead of a copy, and what the arrangement costs you.

Written by the people building it

268MBthe whole volume
524kBone slice
0copies of the scan we keep
Axial computed-tomography slice through a Me 163 airframe, slice 192 of 512Figure 1 · slice 192 of 512
Fig. 1real scanOne axial slice through a Me 163 airframe, from the subvolume this post measures. The cross ticks are every 10 mm, with a longer tick at 50 mm. The frame is 169 mm across at 0.33 mm per pixel.1
01
Two ways to run the job

Two ways to run the job

There are two ways to get a set of scans labelled by somebody else's software. The first is the one everyone knows. You copy the scans to the vendor. Their annotators draw on them. A folder of masks comes back a few weeks later.

The second is the one this post is about. The scans stay in the storage you already pay for. The software reads the slices a person is looking at, over the network, and sends back a record of what was drawn. No copy is made.

We built the second one. Not because the first is hard. Because of the question somebody asks two years later, when a part fails or a model behaves oddly in the field: who drew this mask, and on which version of the scan? If the pixels went to a vendor and the masks came back in a folder, that question is an archaeology project. If the scan never moved, it is a query.

Ask who drew the mask two years later. One arrangement answers in a second. The other is archaeology.

The reason for the whole design
02
What a range read moves

What a range read moves

The volume in Figure 1 is a published scan of a Me 163 airframe from Fraunhofer EZRT.1 As we hold it, it is 512 slices of 512 by 512 samples, at two bytes a sample. Multiply that out and the whole volume is 268 MB. One slice is 524 kB.

When you open slice 192 in the browser, the browser asks your storage for the bytes of slice 192 and stops there. The web has had a header for this since 1999, called Range, and every storage service that copies the S3 protocol answers it. So 524 kB crosses the network, straight from your bucket to the screen of the person looking at it.

Scroll through ten slices and you have moved about 5 MB. Upload the same volume to a vendor and you have moved 268 MB, and then it is somewhere else, forever, on a machine you do not control.

The difference gets larger, not smaller, with the size of the study. A 2,000-slice industrial scan is a bad upload and an ordinary read.

The pictures on this page are much smaller

Every frame in this post is a 512-pixel AVIF image of about 36 kB, because a web page does not need 16-bit samples to show you the shape of a wing spar. All 64 frames come to 2.0 MB, and the label overlays add 0.3 MB.3 The viewer inside the product reads the real samples. This is a blog post.

Axial slice 32 of the volume
z 32 · 19.2 mm
Axial slice 96 of the volume
z 96 · 57.6 mm
Axial slice 160 of the volume
z 160 · 96.0 mm
Axial slice 192 of the volume
z 192 · 115.2 mm
Axial slice 240 of the volume
z 240 · 144.0 mm
Axial slice 288 of the volume
z 288 · 172.8 mm
Axial slice 336 of the volume
z 336 · 201.6 mm
Axial slice 384 of the volume
z 384 · 230.4 mm
Axial slice 416 of the volume
z 416 · 249.6 mm
Axial slice 448 of the volume
z 448 · 268.8 mm
Axial slice 480 of the volume
z 480 · 288.0 mm
Axial slice 504 of the volume
z 504 · 302.4 mm
Fig. 2real scanTwelve of the sixty-four sampled slices, with the dataset's own labels over them. Each cell is one read. In the product each cell would be 524 kB of real samples pulled from your bucket; here it is a 36 kB picture. Scroll it sideways or use the arrow keys.3
03
What we keep instead of a copy

What we keep instead of a copy

Three things, and none of them is a picture.

A list. Where each series lives, how many slices it has, how big they are, and the technique settings that came with the file. The viewer needs this to know what to ask for.

A hash. A checksum of each file, taken when we first index it. If the file changes under us, the next read says so instead of quietly showing you something else. A scan that changed after it was labelled is a fact you want on the record, not a surprise.

The record. Every label event, with the person or model that made it, the person who accepted it, the parent it came from, and the time. This is the actual product. The rest is plumbing.

So if somebody took our whole database and none of your storage, they would have a list of file paths, a column of checksums, and a set of outlines in millimetres with names attached. We are not going to tell you that is nothing. It is not nothing. It is also not your scans, and it is a great deal less than a full copy of them sitting in a vendor's account.

Table 1What crosses the network in each direction, with Nitsor reading from your own storage.
The thingWhere it livesDoes it reach us
The samples in the scanYour bucketNo. They go from your bucket to the browser of the person looking.
The file listYour bucket, indexed by usThe path, the size and the shape. Not the contents.
The checksumComputed on readYes. It is how we notice a file changing.
The labelsOur databaseYes. Outlines in millimetres, with an author and a reviewer.
The review decisionsOur databaseYes. Accepted, rejected, by whom, when, and why.
A release exportWherever you put itYou take it away. It verifies without the scans.
04
What an auditor gets

What an auditor gets

This is the part that makes the whole arrangement worth the trouble.

A release is a JSON file. It lists the label events in order, names the people and the model versions behind them, and carries a chain of hashes so each entry commits to the one before it. Change any entry after the fact and the chain stops matching.

An auditor can check that file on their own laptop. They do not need an account with us. They do not need the scans. What the chain proves is that the list has not been edited since we chained it. It is not proof that we could not rechain it, and we are not going to claim otherwise.

Compare that with the usual artefact, which is a PDF report saying the work was done. A PDF is a claim. A chain of hashes over a list of events is a claim you can test.

Releases with a log and a hash chain work on the hosted instance today.4

05
What it costs you

What the arrangement costs you

It is not free, and a post that only listed the good parts would not be worth reading.

You run the storage. Its uptime is yours. If the bucket is unreachable, so is the slice, and we cannot serve you a cached copy because we do not have one.

Your network is in the path. A slice read from a bucket two regions away arrives later than a slice read from a disk in the same room. Annotators feel that as a small delay when they jump around a series. Putting the storage near the people is the fix, and it is your decision to make, not ours.

Signed reads have a clock. The browser gets a link that works for a short window and then stops working. That is deliberate, and it means clock skew on a laptop can produce a confusing error. We would rather have that error than a permanent public link.

You have to know where the scans are. More teams than you would expect cannot answer that on the first call. The answer is usually worth having anyway.

None of these are surprises we spring later. They are the price of the scan staying yours, and we would rather you read them here than discover them in week three.

Notes and sources

  1. Fraunhofer EZRT XXL-CT Instance Segmentation Me 163, subvolume V5. doi:10.5281/zenodo.10651746, CC BY 4.0. As held here: 512 slices, 512 by 512 samples, 0.33 mm per pixel in the plane of the slice, 0.6 mm between slices, 169 mm across the frame. Windowed for display between the 0.5th and 99.5th percentile of the volume, and never resampled in the plane. back to text
  2. The 1999 date is RFC 2616, which standardised the HTTP Range header. Amazon S3 and the storage services that copy its interface answer range requests on ordinary object reads. back to text
  3. Byte counts measured on the files this page loads, on 28 August 2026: 64 CT frames totalling 1.97 MB, label overlays totalling 0.30 MB, and 35,695 bytes for the frame in Figure 1. The 268 MB figure is arithmetic on the sample count, not a file on this server. back to text
  4. Releases with a log and a hash chain run on the hosted instance at app.nitsor.com. Sign-in is by invitation. Product status lists what does and does not work. back to text

Bring one set of scans. Leave with a record.

Thirty minutes on your own scans, on our hosted instance, no slides. If we are not a fit, we say so on the call.