References
A feed does not hold bytes. A reference points to them. It is a row that names a resource and the location of the bytes inside it. A feed can have several references, such as the same file in a bucket and in an export of that bucket, and the feed describes what they have in common.
| Role | What it points to |
|---|---|
original |
the file or record itself, wherever it was synced from or placed |
preview |
the hi-res JPEG, no longer on its longest edge than the Hi-res size setting, which a thumbnail opens and the image and page analyzers read so they do not render the file again |
thumbnail |
a JPEG as wide as the Thumbnail width setting, for the catalog |
preview and thumbnail are derived. An analysis renders both once for images, video, audio,
PDFs, and captured pages, and stores them in the internal derived store, keyed
<feed id>/<role>.jpg. Audio renders as a picture of its waveform. See
derive for the sizes. That
store and the children store are listed in Resource::INTERNAL. xixo keeps them for itself and
never offers them as a place to store a file. Serving a thumbnail reads the bytes of the thumbnail
reference, so it passes the same grant check as any other bytes.
Everything that counts a feed’s places counts originals only. That includes Feed#reference, the
search document, splitReference, and forgetFeed.
Locators
Section titled “Locators”locator is a JSON object in whatever form the resource needs to find the bytes again, such as a
bucket and a key, a path, or a mailbox uid. locator_key is its stable string form, the path a
person would recognize. A locator_key is unique within a resource. The model validates this, and
a partial unique index on (tenant, resource, locator_key) enforces it, so one object in one place
has exactly one reference. Syncing the object again finds that reference and does not create a
second one.
Noticing change
Section titled “Noticing change”version is the value the resource gives for this revision of the bytes: an S3 or WebDAV ETag, a git
SHA, a Notion last_edited_time, or the digest of a web capture. When a sync reports a version that
differs from the stored one, the reference sets changed_at and clears analyzed_at, and the sync
starts a new analysis. A cached analysis step that finished before changed_at runs again, so an
analysis never describes bytes that have since changed.
Noticing what is gone
Section titled “Noticing what is gone”Every object a sync walks past sets its reference’s seen_at. When a sync finishes, xixo sets
gone_at on each original reference in that resource that was last seen before the sync began,
because the source no longer has it. This does not happen after a sync that was cancelled, ran past
its deadline, was gated, or was a dry run. Nothing is deleted. The feed, its analysis, and its notes
stay, and the item page says where the file is no longer found. A later sync or keep that finds it
again clears gone_at.
Only a full walk can tell what is missing. A walk of only what changed has no information about what it did not visit, so it marks nothing as gone. The exception is a source that reports deletions itself, as the commits since a git checkpoint and a OneDrive delta do. A OneDrive delta also marks a file as gone when it moves out of the resource’s folder.
A reference that was only ever kept by hand has no seen_at, and a sync that does not reach it
never marks it as gone. RSS does not detect deletions at all, because an entry that scrolls out of
a feed’s window has not been removed. A filesystem walk that could not read a directory marks
nothing as gone, because the files it missed may still be there.
source_version belongs to a copy. When an export writes a feed into another resource, the new
reference records the version of the original it was copied from. The next export compares the two
versions and copies the file again only when the original has changed.
Moving between feeds
Section titled “Moving between feeds”move_to! moves a reference to another feed. If that feed already has a reference to the same
place, xixo destroys the moved reference so there is no duplicate. In both cases, a xixo:file feed
left with no originals is destroyed. split! is move_to! into a new feed with the same type, key,
title, and expiry, and the new feed connects to everything the old one connects to and takes its
note. splitReference refuses a feed that has only one original. Export, joining, and leaving are
what move references.
Joining the same bytes
Section titled “Joining the same bytes”digest is the SHA-256 of an original’s bytes. Every original gets one: an analysis computes it
before it reads anything, and a recurring job fills in any that are missing. An upload carries the
digest it arrived with.
Two originals share a feed when they have the same join key, which is the digest together with the owner of the resource. A tenant’s resources join each other, and a person’s own resources join only that person’s, so a feed never lists a personal place beside a shared one. Empty files, originals that are gone, originals on archived resources, and the extracted children an analysis stores for itself never join.
When a digest is written, settle! finds the oldest feed that holds the same join key and joins
the others to it. The joined feed’s connections are added to the oldest feed, its note is appended
unless the oldest feed’s note already contains it, and the later of the two expiries is kept, with
a feed that lasts forever outlasting any date. Its analyses, derived references, and extracted
children are destroyed, because they describe the same bytes. A feed with an analysis still open
is left alone until that analysis starts, because the analysis settles its own feed and stops
without reading anything when the feed joins another. Each join is recorded in the audit log.
Leaving and keeping apart
Section titled “Leaving and keeping apart”When a sync reports a new version for an original on a feed with other originals, that original
leaves with split! before anything analyzes it. The analysis that follows computes the new digest,
so a file saved again with the same bytes joins its old feed and is not analyzed, and a file whose
bytes changed stays on its own.
On the item page, Storage lists each original, and one whose digest matches another original of
the same feed says the same bytes as another place. Keep apart on an original calls
splitReference, which moves it to a feed of its own and marks it kept_apart. A kept-apart
original never joins. A new version clears the mark, so the original joins again once its bytes
match something. Keep apart appears only on a feed with more than one original.
What xixo deletes
Section titled “What xixo deletes”Forgetting a feed destroys the row, its references, analyses, schedule, edges, and extracted children, and reports how many originals it pointed to. It does not touch the resources those originals live in, so the files stay where they are.
The exception is bytes that xixo created. A reference in an internal store, such as a preview or
thumbnail render or a child extracted from a message, deletes its blob when it is destroyed,
because nothing outside xixo created it. A file that was uploaded and never placed is deleted with
its feed, because it was only staged.