An atproto AppView for tracking a Magic: The Gathering collection github.com/eth0net/manaweb
v0.19.0 c10cb404 eth0net

The pile stops shouting

A scanned stack used to take six lines, a name that wrapped, and a dropdown to go with it. It takes two lines and a row of badges now, under a header that has shrunk to a single bar. Grading moved out with it: you tell the scanner once what the box is, and every stack that comes out of it is already answered, instead of being asked again card by card. Foil and condition are presses on the row, and they lock themselves where a printing was only ever made one way. A pile can be thrown away now, with a count of what you are throwing in front of you first. A hot reload stopped keeping two of everything. And a tab's own button lets go of the set you are in before it lets go of the sets. Underneath, the advisory check runs nightly against a tree nobody has touched, `just deny` runs the command CI runs, and a push does not go out unless it passes. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQD5wtP96W8415BBtDXAJsvVDZT+rmwl5EXHarDdxT9v9twJnbV0b8DsctjgXJmF+TE DnYqbqpyZwKR3sRWAoAgI= -----END SSH SIGNATURE-----

v0.18.0 b64f8fd6 eth0net

The List opens at once

A list of thousands of rows carried a modal apiece and now the page holds one, so the biggest set in the catalog paints in a tenth of the time and grows a page at a time as you reach the foot of it. The React Compiler took over the memoizing that was being placed by hand. A card turns over from a control on the card itself, and signing in picks both its client and its callback from the address it is served at, so loopback and the dev deployment each reach their own. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQPMbyjvrfLNpNkvtkb+UZMAsxZqnpQ61dQ1VxIAnbP6UpGpbUjJmO/1IAfgAYieXfj D6fD/Cb/5+Qba/ZZv+cQg= -----END SSH SIGNATURE-----

v0.17.0 8e81aa2f eth0net

The camera draws a box around it

The viewfinder outlines the card it can see, eased corner by corner at the camera's own rate. Signing in stopped meaning reading licence text, a panel closes from its corner or from beside it, and a two-sided card turns over. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQKt+2EDCxVDe/aAl6FvsiLdQ015l6/YfDRF34CYzqiDdtUJrBoSMEMAXx126aARQQj +MqPctAyFvQHR5/fnZLA8= -----END SSH SIGNATURE-----

v0.16.0 17a7fcf8 eth0net

The scanner keeps up with the camera

Asking a camera for 1280 on both sides is asking for a square, and an iPhone obliges. Every frame read 1.6M pixels back for 71ms against 3 to draw them, and a whole read cost 101ms — nine and a half a second where the camera offers thirty. The constraint names one side now, the track settles at 720x1280, and the readback is 3ms: twenty times quicker for half the pixels, so the old size was crossing a threshold rather than costing by the pixel. A read is 28ms and 35 a second, and the capture has stopped being what the scanner can afford. A read answers with the card's corners rather than with whether there were any, so the frame it was taken from comes up with the card outlined on it — solid where the margin would accept it, dashed where it would not, which is the same answer to anyone who cannot tell the two colors apart. That picture holds the viewfinder rather than a corner of it, nothing being aimed between a read and the next press, and pressing it goes back to the camera: scanning again would thaw and read in one press, which reads the card that was just scanned. The panel shuts to the printing it settled on and opens for the runners-up. None of this was visible from the machine it was written on. A development readout times a read by its parts and posts them back, rather than leaving figures to be read off a phone and typed in again, and what it reported first was that every laptop measurement here had left out the canvas grab in front of it. It also priced the case a search actually spends its time in: hunting is 80 query hashes against 32, 64ms against 32, eighteen frames a second against thirty-five. So the lookup is the frame now, and a retrieve that was a rounding error beside an 84ms grab is 34ms of a 59ms search. rustls 0.23.46 closes four advisories at once and carries four crates off windows-sys 0.52 with it, leaving a skip in deny.toml with nothing left to skip. The readout, the capture route and everything they import are still dropped from a production build, and `bun run sealed` still reads the bundle back to prove it. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQGJjkQQN6RRtwf3qcDM+45rV0fZ9wNt1BJBfx/4ea8tck9grZm3HkcwlWnwuczwIOL ZMbGzzB2MteRC84DZKNgs= -----END SSH SIGNATURE-----

v0.15.0 36b9fed6 eth0net

No week comes back

A sync keeps a row per attempt now, written on the pool rather than inside the transaction a refusal rolls back, so the week it turned a file down is readable afterwards instead of gone with the catalog it declined. Every bound the sync refuses on rested on a single observation until now, because `bulk_sync` holds only the last one. A download that stopped arriving is told apart from a database that failed, and the log says which attempt it is on rather than reading the same at the first and the fortieth. ManaBox calls a column Purchase price and fills it with what a copy was worth the day it was added. 251 identity keys repeat in one export and 216 of them differ in nothing else, which is a market moving rather than a collection. The import says which it is reading and offers the other, a dropdown on the file rather than a setting nobody would find, and an export names every field it has no column for before it writes rather than leaving it to be missed after. A cache synced under the old order repairs itself where it stands — 147,362 rows renumbered in nine seconds on the server, each card's representative printing read back off the result so the two cannot disagree — which holds it consistent until the re-sync that actually moves it. What a file is called, what a note says and what a tag reads are each cut the way the lexicon counts them, by byte or by grapheme, rather than the way a browser does. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQH9+h7lblORcVnUhQetevvTw6QMl0jN6afju1vDbz8OXvDuTFNJ7QKG6bF7Pyi3/1O HoAQk4qGhVDuVRjjYhIwo= -----END SSH SIGNATURE-----

v0.14.1 ad0e046e eth0net

One name each

Eight cards came out of the catalog named after themselves twice — Blood Crypt // Blood Crypt — and ManaBox refused every row carrying one. Scryfall shipped a reversible Blood Crypt in the same expansion, on the same day, as the ordinary one, so the two tied on every count the printing order knew about and the order of the file decided which named the card. A card is no longer named after the printing folded back on itself. ManaBox's export grew a Signed and a Proxy column after we last read one of their files, and we read neither, so a current export lost both without saying so. A bound column is no longer a required one, per format, so a file from before those columns still reads and one from after is read whole. Their importer also turns down the Phyrexian their own exporter calls English — an export says how many cards that is, and offers to say English too. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQKc1nLgRwcp2X8nw06U6HY9k4oYGncHfBzbG3E5B24toAXUzLgY4NGAfO+++qmwPSN hQbQU0Pw3931ieoQdUbgY= -----END SSH SIGNATURE-----

v0.14.0 9d39817e eth0net

Easy to leave

A collection comes back out as a file. ManaBox's own shape, held to their exports row for row — 403 of 403 match outside the id they issue and a currency they print beside a blank price — or a shape of ours carrying a column per field a record holds. A format is a table of field against column, so an export is that table read backwards, and the next tracker is a binding rather than another writer. Writing a file has to choose where reading one did not. Copies go out one row per lot and never more than are held, the rows are ordered so that two exports of an unchanged collection are the same file, and whatever the format has no room for is named before it is written rather than found missing afterwards. An import reads more back than it did: whether a card is a proxy, the day a lot was come by, and when a stack was last changed — which survives the trip except where a row joins a stack you already hold, because that one really did change today. A sync refuses a file no record of which carried a field it reads. Mana value, type line, legalities, games and finishes are each optional or defaulted, so a renamed one costs no record, skips nothing, comes back the same size as last week, and ships a catalog where every card has no mana value, or no legality, or no finish to pick. Zero is the whole test and wants no calibration: a rename takes a field from every record at once, so one record still carrying it means the cache is still reading it. The committed engine is no longer compared byte for byte in CI, where it never once passed. The same compiler on two hosts emits modules that answer alike and differ at byte 203, so the comparison belongs where both sides are built in one place — the push that deploys, which is also the last moment anything can stop a drifted module going live. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQBK35NhX2a4DRgog5obXP3E/0UrCyqHd9fdntZiNiJe4HEhVynaqpUSB9e9TJD2O9d C0tJ3YPRuy5G4KRvt+4A4= -----END SSH SIGNATURE-----

v0.13.0 a9228be4 eth0net

Detection explained

A detection carries every measurement it weighed now, and the first check that turned it down, and a tally runs that over a directory of frames at any flood step. Asked what drops a card tilted away from the camera, the answer is the hull test — and a lean is not what it refuses. Drawn at a known angle a card clears every check out to 60 degrees, while the photographs that fail have a silhouette gone soft, which grows the hull faster than the four corners fitted inside it, so face on in poor light reaches it as readily as tilted does. A sync that lost too much of its file no longer reaches the catalog. More than a hundredth of the records unreadable, or a catalog more than a twentieth shorter than the last, and the transaction rolls back with what is published left alone. The skipped count has said since it existed that Scryfall changed something, and until now nothing read it. Past 44.3 degrees a card is read a quarter turn and nothing says so, found by drawing one at known angles because every photograph in the set is face on or turned in the plane of the table. Written down rather than fixed, along with what a scan sent back from a phone would take and what it would break. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQP/3/zCQMjzL5YLiU1nFi9oDUUPxRUuqqVYfAabenWsaZ8HT7SkmRXri2G1+H6KmVt jz0xfWkNYKYUNq6nSZ6gI= -----END SSH SIGNATURE-----

v0.12.0 fa39c293 eth0net

No longer a file somebody remembers

The server fills its own artwork store now, a capped run each refresh, so a scan stops going stale a set at a time. A store copied in is a shortcut past the first build rather than a thing someone has to remember. Scanned cards carry a condition, graded for a box and corrected per stack. A container stop reaches the graceful shutdown rather than the kernel's default, and CI holds the committed engine to the source it was built from. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQFHCE0MnuUgcPAp0XDpOtoMPiSRYFkejaUvzb/U4zg4RbJnWm2eYh1RauU5db13bUj yzja6IYQOY3fX0LqtCTAs= -----END SSH SIGNATURE-----

v0.11.0 585836ac eth0net

A scan you can keep

A scan lands in a scratch list the tab outlives, and the list is reviewed before any of it becomes a collection entry: a stack per card with its own count, the printing and the finish pickable, a catalog search for a card the reader never matched, and a commit that drains through the same import the CSV path uses. An uncertain read waits to be agreed with rather than arriving in the list on its own — keeping one is also how a wrong read reaches the list to be put right, so it cannot stand as naming the card. A settled artwork is not a settled printing. A surge foil photographed through a sleeve under glare answered well clear of the floor, on the right artwork and the wrong printing: two printings share that one illustration and no distance tells them apart. The margin now settles a printing only where the artwork it won on carries one, and where it carries several they all go in front of whoever is holding the camera. Reads that go wrong can be sent back, too — a development build holds the last few frames for an hour and the review posts one with what the reader made of it beside what a person says it was, which is how the scoring corpus gets the shots nobody would have thought to keep. Also: flip cards read as colorless on their flipped side, a face carrying neither colors nor a cost now taking the card's as the rules do. The finishes table is built from the rows like every other taxonomy, so a finish nobody wrote down reaches a client rather than being dropped on the way. Signing in from a phone over a tunnel works, and says so when it cannot. Handle resolution goes through a public service by default, and through one you name instead. The compiler is pinned for a checkout and for CI, after stable moved and `just check` passed what CI refused. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQCJVti77M460sQxpqvX2WD4dOvctGZAUBF7FXGZ/V4Uc3sjEwucneiHhwWgVgmyspu KCdR6NOKXdVt/+Xa4GTgM= -----END SSH SIGNATURE-----

v0.10.0 25790291 eth0net

A camera that reads a card

The scanner is in, end to end: perceptual hashes of every artwork Scryfall serves, built into a store and published beside the catalog, and a scan tab that is the camera itself — a frame read at 1280, a card found in it and straightened, and the printing it names with how far off the runner-up was. Where that margin is too thin the runners-up are offered instead of a guess being taken as an answer. The reading engine is Rust compiled to wasm and reached over a C ABI, so the same calls will serve a native app; it is committed rather than built by whatever deploys the app, and held byte for byte to what its source builds as well as to what a native build answers. What a scan finds still lands nowhere. There is no scratch list and nothing writes a collection entry, so this is a scanner you can point at a card rather than a way to add one. A card tilted far enough that its outline stops being a rectangle stops being read, which no photograph in the scoring set covers — captures from a phone now come back to the dev server so the ones that fail reach the corpus. Also: the dev server was serving the whole checkout over `/@fs/` because of a lockfile at the root, which a tunnel made public; it serves the app and its dependencies now. A migration edited after it had been applied made every existing cache refuse to open, and a test holds each one to its checksum so the databases get repaired in the same change. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQKp/W9JCdcBugFpS3Q+9/qIgNO97ucH04ND5JPpz+YbqzBKzPuKM4VJo8Yga5ZVg2e JOQAI9ftstKegNQ5roLA0= -----END SSH SIGNATURE-----

v0.9.2 c1459da9 eth0net

What four reviews found

Fifteen commits over the tree, and the ones that would have bitten are all in paths nothing exercises until they fail: a bucket with no manifest could never receive its first catalog, because the sweep that makes room for an upload opened by reading the one it was supposed to produce. An import ended itself on any dropped connection, a TypeError from fetch having been read as a verdict from the PDS. A part re-sent after its answer was lost wrote those cards a second time, and a discarded import came back on the next app open. The catalog export is untouched — a full sync through the rewritten line reader hashes to the same two filenames — so no client re-downloads anything. The docs now say which of what they describe is built, the justfile says what each recipe does, and `just hooks` exists, which CONTRIBUTING.md has been telling people to run for some time. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQOaA5Uq+wmzaH2GeRLxN2UufDqJ5aO7Ah2/9/zv3j17+pEkTSJFbA3SJSKNtWlpBYH 9ByPkp6cs3G9ST3Cl3/AM= -----END SSH SIGNATURE-----

v0.9.1 49c9e25e eth0net

A migration makes the cache stale

An upgraded container read its cache as current, skipped the sync and exported a column that migration had just added, publishing nulls over a correct artifact. bulk_sync now records the schema it synced under, so a cache from anything earlier reads as unsynced: the refresh downloads again and the export refuses. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQMy/+Z+13H6yCcppueBIYSyJySDCLjElcnHHAlxXr2vxAEdUVgl98Xn6eb9Tn7HX/A DSJlFLkug3BAr3jX/ilgE= -----END SSH SIGNATURE-----

v0.9.0 9eba65e5 eth0net

Both sides of the card

The cards file carries a two-sided card's faces and its keywords, and the prints file names which artwork each printing shows — the three parts the base pair was costed for, landing together because a format change costs a re-upload of everything. A transform card could answer nothing about its colors, cost or power; the queries where our search disagrees with Scryfall's went from eleven missing results to one. The client reads past a column it has no reader for, so an artifact may be published before the client that reads it. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQItXWwZ0rgfgrMe4qkuOGMlN1ZdFvyaZQrCqP/NB7Q1XdqtHeQZVa/V8cFPhBVMrD7 4dMwhRzYhNM4ZfsPfY0QU= -----END SSH SIGNATURE-----

v0.8.0 b0d0ebb3 eth0net

The artwork, and a faster export

A printing now carries which artwork it shows, the thing an art match narrows to and the first the scanner will want from the cache; nothing reads it yet, and it fills on the next sync. The export stopped sorting a hundred thousand joined rows to find the order it writes in and reads an order written at sync instead: 1.64s to 0.80s, for the same bytes. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQJepGPTEXgA/W3q40ZHAdMoxv7PtcXzCGbEksjwoh1Cc4q2qSznMr2RZKus9iTVFtW UykWtAq0l1ge+75cx8LQA= -----END SSH SIGNATURE-----

v0.7.3 07b3e82b eth0net

The client reads past what it does not know

A file may carry columns this client has no reader for, which is the only way one is ever added: a client already loaded fetches on its own schedule, so refusing a field list that is not exactly the one it reads takes the catalog off every browser already out there. A column that moved is still refused. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQIFxqGYRbYYJY4QdKEjtznPujXkvhGJMhX1x2sd6es/GIXMAucKHTJuNgQ5VNSFEdC n+pC8Mu8ELNkh+0ah2ZQE= -----END SSH SIGNATURE-----

v0.7.2 4e034e0b eth0net

The avatar renders

A profile picture is read through the session and drawn from an object URL, which the policy refused, so it has never once appeared. The dev server names the catalog's own origin for the same reason. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQLqFfrhpLCl3Nm5U23FG/26l2PxfXPdTsbt+Sp3xQsJuBZdQEbRHOSzLVk3dbXDJz+ rvqCTkbnL0FLQcDZBmEA8= -----END SSH SIGNATURE-----

v0.7.1 292925ab eth0net

An app, not a page

The shell holds the viewport and nothing outside it scrolls, and every icon the app ships is composed from the one drawing — inset where a launcher masks it, a silhouette where it throws the color away. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQGRiNvvsWOXGz1QP7/yT/5dyqXH5rz9js6j3reZ55ngFi67SJHG1Uj1bxSqXsjkyT6 myzOUidRQb/rk+AnVQuwc= -----END SSH SIGNATURE-----

v0.7.0 6da8666c eth0net

v0.7.0 -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQJgBDjKMd21f+3ijU30NdG8+eHbhkX37lKAS0Ii/t5qytN8Ue8LX30maezInvyTUuN 4k9OFuDcniy7zUsVkIDw8= -----END SSH SIGNATURE-----

v0.6.0 3bb06e0c eth0net

v0.6.0 -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQBZ6nxVGte5LdSUeIXr26kyL06VzkZ54oSsKNeHVVr7/tJpNJlhiWkMzKMpOJoXaE/ PpDC9W7iVCKMAw5PqM3Qg= -----END SSH SIGNATURE-----

v0.5.0 59ed2ac7 eth0net

Deployed

The app is on Pages and the catalog in R2 behind its own domain, each artifact set under a prefix of its own so a scanner index can land beside the catalog without either claiming the name a client reads first. The binary uploads after a refresh rather than handing the directory to a shell command, which is what a host running a container with no checkout can actually do, and it holds the credentials itself. A deployed catalog can be held to the headers a client needs without a checkout to compare against. An export that names printings by set and collector number resolves them against the catalog in one pass, so a file carrying no Scryfall ids imports like one that does. Fixture records seed a dev account without touching the UI, and CI validates them against the lexicons before a seed can write half of them. Assets are hashed and never revalidated, the workspace has one lockfile, and the dependency tree carries no default feature nothing reaches. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQEdlFVZrFoH75GHOfkhByS2EelaIP07n7RA0pl3dc+RlmwBn4Rrt/WDHLJIEHRMSti 8yI/0a+pSK8tEaRYjTDgs= -----END SSH SIGNATURE-----

v0.4.0 e439820f eth0net

A collection, imported

Reads a ManaBox export into stacks, plans them against what the account holds and puts the whole file in the repo as import parts in seconds — three calls for 4,333 stacks — then drains them into card records over hours at whatever the PDS will take. The repo holds the work rather than the device, so closing the tab, wiping the browser or signing in elsewhere all resume. Cards still waiting in a part count as owned wherever they are shown, and copies can be taken off one before it lands. The server picks record keys, the collection paints from its last read before the repo answers, and a tab remembers where you left it. Measured end to end against a rate-limited PDS: 4,336 rows in, 4,333 records out, one receipt left behind. Build order step 5 is done. Fixtures and deployment are what v0 still wants. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQAOwg/vFXM5aLbAes7f8RptqGMK3e0AWuaRWlKIQ9Xk/9Js6sDIjGwKj6gS3iCXdN5 Cv2t67Skpl1eW4hISRewU= -----END SSH SIGNATURE-----

v0.3.0 f47152b3 eth0net

The collection, editable

Signs in over OAuth on granular scopes, reads the account's own records and writes them back: add a printing or another copy, take one off, regrade it, move it, tag it, note it, mark it a proxy. Containers are an opt-in layer with a chosen destination, and deleting one returns its cards rather than orphaning them. Four routes behind a bar that stands up as a rail on a laptop, a printings gallery you pick by art, and set completion counted from what you hold. Record types are generated from the lexicons. Build order step 5 has its write half. CSV import and deployment are what v0 still wants. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQHJzwazoLLqDBAJlmAFhT0ezdQAmCdXz+Nq99ozEynm488TM/2afYU9cJE8Nd3e6wf 9n2LtoLn7rKyFR1LCjEQE= -----END SSH SIGNATURE-----

v0.2.0 1011bc08 eth0net

The catalog, browsable

Reads the 3.99MB catalog into IndexedDB and searches 37,564 cards in the browser, ranked on EDHREC popularity where there is one and reprint count where there isn't. 988 sets to browse, printings filtered by language, and Wizards' own mana symbols with the notices that obliges. The artifact gained stats, flags, artist and rank; its print ordering became deterministic. Build order step 5 has its read half — nothing writes to a PDS yet. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQMDg4yXsJALIZQkZthcBgnvdYJSYTWM5lrkuHI7vAWW5A/dUejpjwGHMmX4aXe8/V2 x3PG/LIl1L4HkEjxAd7AI= -----END SSH SIGNATURE-----

v0.1.0 3ebb77fd eth0net

The card cache, and the catalog a client needs

Streams Scryfall's Default Cards into an 81MB SQLite cache, exports the 3.67MB catalog from it, and serves that for local development. Lexicons enumerated and validated against atproto's own implementation. No client yet — build order step 4 of 6. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgD8oXmYAt6UaSn3AemwmXd+yv1d zVfGqhV6IJaTUsPScAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQI/8M6NpuRVDRI/D54Pisd1UZ8IiOITSD9yt9+MbOTJx9LfDLpkZKqVA8d58oxbvfY ZbovEk+quc05LP5dmH/wM= -----END SSH SIGNATURE-----