Beta journal

A new build ships every day, which sounds like discipline and is mostly compulsion. This is where I write down what I did and, more to the point, why — and then, because I don't wholly trust my own version of events, everything under the diary gets dredged straight out of the commits and the open tickets. The prose can be in a mood; the facts can't. Every line links its ticket, so you're welcome to watch me argue with myself and lose. Updated August 10, 2026.

August 11, 2026 — Twenty-five cuts, one confession

Yesterday was the biggest day this app has had. Twenty-five changes landed, each one suite-green before it merged, and the shape of the thing is different this morning. The worst file in the codebase spent months as a four-thousand-line junk drawer; its verbs live in named rooms now — rating, culling, committing your typed words — and what still sits in the old file sits there on purpose. We wrote the ruling down: the hub stays a hub. Extracting it would have been surgery for the surgeon's sake.

The film work grew its best trick yet. Midtones by roll reads your scans on your Mac and tells you, in numbers, how each roll's midtones sit against your whole library — stops, not grades, and never the word underexposed. And rolls learn their year now: date two frames of a scanned roll by hand and the app offers that year to the frames still wearing the scanner's stamp. Unanimous or silent. Your own assertion always outranks the inference. Same discipline on people and pets — record that Winston lived 2004 to 2016 and an undated photo he's in can earn a decade tag, but only when the window truly fits one decade. The math abstains more than it speaks. That's the point.

Two doors opened. Subjects — a pane listing every person, pet, and thing you've recorded years and places for, including the orphans whose tags you deleted long ago; they were unreachable on disk before, and now they have an edit door, a forget door, and a quiet badge instead of a warning color, because an orphaned memory is not an error. And the story page finally says who: Kate · 1948–2022 · 46 in these photos. Facts side by side. The sentence stays yours to write.

The confession. Our help pages ship with a mirror on this site, and a gate is supposed to catch the mirror going stale. It caught it — and then sat red for four pushes because the alarm rang in a room nobody was standing in. Fixed the drift, then fixed the habit: every push now gets its verdict checked, by rule. And last night's build never uploaded — the build machine hung for a day and everything queued behind it silently. Kicked it loose this morning; today's build comes late and honest rather than on time and imaginary. Also new since yesterday: your taxonomy packs export as files a colleague can import, the Help menu grew a door to the discussion board, and this journal grew a feed you can subscribe to.

August 10, 2026 — The loop runs both ways

Yesterday the app grew its first real bridge to somewhere else, and I spent the whole day making sure the bridge can't lie. Publish to Flickr went in before lunch: mark photos, run the command, they land on your own Flickr account wearing your titles, captions, tags, and license. The part I care about is what it refuses to do. Every upload states its visibility, its safety level, its license — outright, every batch, chosen on a sheet you confirm. Nothing inherits from whatever your Flickr account settings happen to be. Your named people's tags stay home, held by the same fence that keeps them out of every online lookup. I wrote that fence before I wrote the upload button, which is the only order that never leaks.

By evening the bridge carried traffic back. Check Flickr for Updates asks Flickr — your ids only, nothing else travels — what your published photos picked up over there, and hands the answers to you as a list you tick. Tags you typed on Flickr come back checked. Titles and captions come back unchecked, because an empty field here might be a deletion you meant, and because Flickr auto-titles untitled uploads from filenames — the app now says "looks like a filename, probably not a real title" right on the row instead of letting IMG_0042 dress up as a suggestion. And in tonight's build: Match Flickr Archive, for the photos you uploaded years before this app existed. It reads your photostream list page by page, matches on your Mac by two signals — the title that is your filename, the taken-time that agrees to the minute — and refuses everything ambiguous. A wrong link would poison every future suggestion, so when the evidence argues, the answer is silence.

One save worth confessing. The Japanese pass over the new screens nearly localized the copyright sentence the app embeds in exported files — Lightroom and Flickr expect that sentence in English, and a Japanese UI would have quietly changed what your files say to the world. The sweep's own audit caught it before it shipped. The fix isn't a note saying don't; the file-writing path now composes from English by construction, and the interface labels translate freely above it. Make the careful thing structural, again.

The unglamorous work: took the app's worst file — four thousand lines of everything — down to twenty-six hundred across twelve careful cuts, each one proven to change nothing a keystroke does. Suite green thirty-some times yesterday. The app reads thinner tonight. It behaves exactly the same, which was the entire point. In tonight's build.

August 9, 2026 — Stopped guessing and asked Photos

The app had a rule I was proud of. Rename a keyword to a spelling Photos can't tell from the old one — cafe to Café — and the rewrite would delete the keyword outright, add and remove cancelling each other on photos that can't hold both. So the rule skipped the write and told you why. Careful, protective, tested. Built on a fact nobody had checked.

Because the code deciding "Photos can't tell these apart" also decided ガ is カ wearing an accent. It isn't. That mark changes the word — カード is card, ガード is guard — and a Japanese user renaming one to the other got a toast saying Photos treats them as the same keyword. False, and delivered in the one market this app aims at. Ticket sat there flagged unverifiable, needs a Mac with live Photos. I have a Mac with live Photos. Tagged a control frame カード, then ガード, asked Photos what it held: both. Distinct. No folding. Asked about cafe and Café while I was in there — also distinct, which means the original fact under the whole gate was wrong too, shipped by me, tested by me, verified by nobody. Kana renames go through now. The accent skip stays, harmless either way. Cost of the actual experiment: four minutes (#1988).

Other thing today is a fence for a thing that doesn't exist yet. Publishing straight to Flickr is coming, and the app knows names — your kid's name is a keyword because you tagged their face once. Day the upload button exists, that keyword wants to ride along with the rest. So the plumbing now refuses: any publish to a third party drops your named people from what leaves, and the code physically can't be written without answering who stays home. Your own folder exports keep every word — your disk, your names. Built the refusal before the button, which is the only order that never leaks (#1965).

Friday I ran the whole app past six hard graders — store rules, privacy law both sides of the Pacific, crash discipline, brand. Three findings. All fixed by dinner. I'd feel better about that if one of them hadn't been an App Store rejection waiting in a Settings pane I'd forgotten was visible. In tonight's build.

August 7, 2026 — The app kept doing quiet harm

Spent the day reading my own code back and not liking what it did when I wasn't watching. Two things, same shape: the app helping itself to something it had no business touching.

First one's the bad one. Type a caption on your iPhone — the real kind, the sentence you'll want back in ten years — let it sync to the Mac, then open that photo here mid-session and the caption field shows empty. Not because the caption's gone. Because I never read it: the app cached the title, decided that was enough, and left the caption sitting there unread, looking like nothing. You type over the nothing. Worst part waits for ⌘Z — undo had nothing to put back either, so it wrote empty over your sentence and called it a reversal. The memoir field. The one thing this whole app is an apology for losing in the first place. Fixed now: before it overwrites a caption it can't see, it goes and reads it, so undo always has the real thing to hand you. Single photos and batches both (#1921).

Second one costs money instead of memory. Click a photo iCloud had quietly evicted off your Mac and the app would reach up and pull the whole original back down — not to show you, just to squint at it for a tag or crop out a face. Megabytes you never asked for, on whatever connection you're on, for a job that didn't need the original at all. Every one of those background looks stays local now, by default — a new one can't forget the rule, because the rule is the default. If the app wants your original down from the cloud it has to say so out loud, and nothing that runs on its own gets to (#1922).

Both were mine. Both shipped quiet and stayed quiet until I went looking. Same lesson I keep relearning: make the careful thing the thing that happens when nobody's paying attention. In tonight's build.

In the pipeline

  • The junk drawer is empty. The app's worst file — four thousand lines of everything last week — finished its decomposition: every verb family now lives in its own named, tested type, and what remains is the hub they all report to, kept on purpose with its laws written at the top. Twenty-five suite-green merges in one day; behavior identical; the code finally reads like it works (#1160).
  • Midtones by roll: pick your scans apart with numbers, never grades. Each roll's midtones read on your Mac and set against your whole library's median — "−0.7 stops vs library median," coverage stated honestly when frames are still in iCloud, and none of it ever says a word like underexposed. Rolls learn their year too: hand-date two frames and the rest of the roll's scanner-stamped frames get offered the true year — unanimous or silent, and your own roll assertion always wins (#1908, #823).
  • Subjects: everyone and everything you've recorded details for, in one pane — people, pets, things, including the orphans whose last tag you deleted years ago. Edit, forget, or just look; orphans wear a quiet "No tagged photos," not a warning color, because an orphaned memory is not an error. The story page joins in: Kate · 1948–2022 · 46 in these photos — facts side by side, ages computed on your Mac, never exported anywhere (#2032, #1904).
  • Packs go both ways now. Export any taxonomy pack — yours or a built-in — as a plain JSON file a colleague drops into their own TAG Lens; the format is frozen and documented, exports are byte-stable, and a re-import can't silently impersonate a built-in. The Help menu grew a feedback door (the discussion board, the journal), and the journal grew an Atom feed (#1899, #1875).
  • Export to Folder now offers to save a whole batch as JPEG — a clean, opens-anywhere folder instead of a rummage-drawer of HEIC and JPG and RAW — and it never touches your negatives: any RAW copies through untouched into a “RAW Originals” folder beside the JPEGs, and a photo that's already JPEG copies as-is, never recompressed. Keep-original stays the default and stays byte-exact; the JPEG box is one popup click, and the panel says plainly which files are copies, not originals (#1907).
  • Teach TAG Lens your own field, and hand it to someone else. Import as many community-authored taxonomy packs as you like — a plain JSON of your terms and their broader words — and they suggest like the built-ins, so a plankton biologist can give a colleague their plankton pack and it drops right in. Every import shows exactly which of your terms override a built-in and what new top-level categories you're adding; a stranger's pack can't hijack a built-in's name or root a term in nonsense; it all stays on your Mac (#1899).
  • TAG Lens can find the dust on your scans. Pick any frame from a roll and check it for recurring marks — a speck sitting in the same spot across the roll's frames is debris on the scanner glass or the film itself, never anything in the pictures. It reads each frame on your Mac, writes nothing, never pulls an original down from iCloud, and does exactly one thing with what it finds: shows you the frames. The retouching is yours, in your editor. Needs at least eight frames to be sure, and says so plainly when some are still in iCloud (#1908).
  • Tell TAG Lens where someone — or something — lived, and it helps place their un-located photos, but only when your own photos vouch for it. Not just people now: name a pet, a house, anything you've tagged (Winston the dog), record where it lived and when, and if most of your located photos of it already cluster in one place, the app offers that place for the ones carrying no location at all. It never guesses from the bare fact — with no geotagged photos to agree, it stays quiet. Years work the same way: a photo dated after Winston was gone gets flagged, never a date invented from thin air. On your Mac, preview-first, ⌘Z undoes (#1904).
  • Your titles and captions finish themselves from your own past ones. Type the opening of something you've written before and a “Complete:” line offers the rest — the wording you use most, first — so a batch that shares a caption collapses to a keystroke and the library stays consistent. It only ever finishes what you're already typing, and Return still commits exactly what you typed, character for character (#1903).
  • TAG Lens shows you your own library back. Open Library Analysis and it lays out which cameras and lenses you actually reach for and where your apertures, shutters, ISO, and exposure compensation really cluster — you shoot the Rollei a third of a stop under without ever deciding to. Pure counts over the EXIF you already have, no AI opinion, opt-in and kept out of the tagging loop; every camera and lens links a browser lookup so you can go read about your own gear. The first dividend of keeping your data clean (#1908).
  • Get your originals out, not just JPEGs. Export Originals to Folder copies the actual masters — RAW and HEIC untouched, never re-encoded — into a folder you pick, with a plain metadata.csv of everything you tagged them. The archival box a working photographer can trust: real negatives shelved with their metadata beside them, distinct from the upload path that flattens to JPEG. Nothing leaves the Mac but the files you're copying (#1907).
  • TAG Lens can spell-check your tags. Off by default; switch it on and Consolidate Tags also flags the lone typos your Mac's own dictionary is sure of — the one misspelled “egret” in a thousand tags that had no twin to merge against — free, on-device, nothing sent. You review and approve each fix, your people's names and every term you imported stay walled off, never “corrected,” and ⌘Z puts it all back. The honest answer to a library full of garbage tags (#823).
  • Your work leaves the app signed. Set your name, copyright, credit, and a license once — All Rights Reserved by default, the whole Creative Commons set on the menu — and every photo you export or share carries it embedded as IPTC, the copyright block Lightroom, Bridge, and Flickr all read. Never written into your originals; ownership just rides inside the file. The thing a working photographer can't ship a single frame without.
  • A solid pass, earned the hard way in a day of live testing: ⌘Z genuinely restores a caption you overwrote now (it was quietly lying before — the receipt promised an undo the keystroke never delivered), a burst culls and tags as one unit instead of stranding the frames you can't see behind the top thumbnail, and the sharp preview stops dropping to a blur after you tag an iCloud-stored photo (#1912, #1905).
  • TAG Lens now tidies while you're away: an opt-in background pass (off by default) warms the search and suggestion indexes only when your Mac is idle, plugged in, and cool — and yields the instant you touch a key. Interrupted work resumes where it left off; nothing is ever lost to a pause (#836).
  • The Flickr loop is real: mark photos “For Flickr,” publish to a folder, and every tag, title, caption, and star arrives with them — drag the folder into Flickr's uploader and your photos land pre-tagged. No account hookup, nothing sent anywhere; your files, your upload (#1749).
  • The Flickr loop shipped whole, and now it reaches your history. Connect your own account once, mark photos For Flickr, publish: they arrive wearing your titles, captions, tags, and license — you choose who sees them every batch, nothing decided by your account's defaults, and your named people's tags stay home. Check Flickr for Updates brings your Flickr-side work back as a review sheet you tick. New tonight: Match Flickr Archive finds the photos you uploaded years before TAG Lens existed and links them — matched on your Mac by filename and taken-time agreeing to the minute, ambiguity refused outright, one ⌘Z to unlink — so your old archive joins the loop too (#1749, #2010).
  • Point your own local AI at a photo with no location and it'll guess the place — the photo never leaves your Mac, only the guessed name gets looked up, and it writes nothing until you press Use (#817, both tiers now shipped).
  • Teach TAG Lens your own field. Import a taxonomy pack — a plain CSV of your terms and their broader words, or a JSON file — and it suggests them like a built-in: tag a Copepod and “Zooplankton, Plankton” come along, so a search for plankton still finds it. Import as many as you like, toggle or remove any, and your terms win a name clash — it even tells you which of yours overrode a built-in. Nothing is sent; it all stays on your Mac (#1899).
  • Stories got their room: click a story's card and the memoir opens — your words leading, the photos gathered beneath, and chips linking every story that shares them ('Shelf 2024 · 3 shared', one tap hops over). Rebuilding a memory now has a page (#1108).
  • Tell TAG Lens 'Roll 12 was 1987' and every scanned frame still wearing its scan date offers the true year — one assertion, one review, one ⌘Z (#823). And TAG Lens speaks Japanese now — every screen a Japanese speaker actually reads, start to finish: the core surfaces, every settings explanation, every error and toast and count, and all 49 taxonomy pack names (軍装品, 貨幣・古銭…). Your own words are never touched, and a build gate keeps a mistranslation from ever crashing the app (#1035, #1897).
  • Film shooters: the roll workbench shipped (#1831). Name a roll (“Roll 12 — Canon AE-1 · Tri-X 400”), assign your scans, and every frame wears an honest “Shot on” row — asserted by you, never forged into the file. Filter to a roll, stamp its tags in ~6 keys, and it all rides your backup file.
  • Your scanner can't lie anymore: when the EXIF camera field names a Perfection, CanoScan, Noritsu or friends, TAG Lens says “Scanner”, treats the file date as a scan date, and offers the group date repair built for exactly those photos (#823).
  • macOS 27's first-party Photos writes (#1835). Star ratings: landed — TAG Lens already promotes your stars into Photos on the beta OS. Keywords and captions: Apple pulled that half from the latest beta SDK (it still exists under the hood), so the AppleScript bridge keeps the job while we re-check every seed to GA.
  • Apple's new on-device model, benchmarked day one: 36% recall on the control corpus — beats a hosted frontier model on our own prompt, 908ms a photo, free, nothing leaves the Mac. It also refused five famous war photographs, which matters for a memoir app and is now a design constraint on the future built-in tier (#1843).
  • The AI bake-off, round one: Claude Fable recognized 31 of 44 famous photographs cold (and named the exact Snake River overlook); Haiku delivered correct tags at a fifth of a cent each; free local models still win the plain-tagging axis (#1874). More columns as keys arrive.
  • Species by name is on the way. Our own grader caught every AI we tested topping out at “some kind of bird” — never the actual species — so an on-device model that names it to the Latin binomial is coming: opt-in, downloaded once, all on your Mac, nothing sent anywhere. The recognizer seam and the grading axis are built; the model is the last piece (#1137).
  • Control photos install themselves — a beta onboarding step that downloads the benchmark album (checksum-verified, consent-first) so every tester shares the same known-answer test bed (#1873)
  • Recognized famous photographs import their documented title, photographer, and tags instead of an AI guess (#1872, opt-in, first slice landing)
  • Control corpus keeps growing — public-domain benchmark photos that keep every AI honest (#1834)
  • Opening the beta up: GitHub Discussions, a public TestFlight link, and the Flickr angle — exported keywords arrive there as tags (#1875)

Recently fixed

  • merge the journal Atom feed — subscribable, deterministic (#1875 S3)
  • the journal grows an Atom feed — subscribable, deterministic (#1875)
  • merge the shareable-pack slice — schemaVersion, frozen format spec, per-pack Export (#1899)
  • a pack is a shareable artifact — schemaVersion, frozen format spec, per-pack Export (#1899)
  • merge the year-sanity validator — both fences share one rule (#2033)
  • one year-sanity validator, both fences — the future-year typo can't flood the sheet (#2033)
  • merge capture-at-intent — the live fallback dies and the ⌘↩ twin collapses onto one resolver (#2017)
  • merge the phash content token — an in-Photos edit invalidates the fingerprint (#2014)
  • merge the sweep half — 29 menu keys, Undo format, ring labels, roll-year rationale, a11y join (#2035)
  • capture-at-intent — the date commit's live fallback dies and the ⌘↩ twin collapses onto one resolver (#2017)
  • phash records carry the content token — an in-Photos edit invalidates the fingerprint (#2014)
  • the sweep half — menu keys, Undo format, cleanup plural, roll-year rationale, a11y join (#2035)
  • merge the normalizeKey fold discipline — shares(entity:) and six sibling entity folds (#2040)
  • shares(entity:) joins the normalizeKey fold — one discipline across the entity seams (#2040)

Known issues (open)

  • #2047 [stories][dates] Year-only placeholder dates leak confident 'Jan 1994' spans into story subtitles
  • #2046 [stories][place] The place leg starves: transient focus-only placeByID feeds the library-wide thread pass; sharedPlace dropped at keep; help oversells
  • #2045 [stories][display] bindSummary renders 'near Cambridge, Ma' — .capitalized instead of the displayPlace fix its sibling got
  • #2044 [a11y] Audit bycatch from the 2026-08-10 surfaces — kind glyphs unlabeled, silent import report, three polish items
  • #2043 [a11y][focus] Announcement seam keys on index while refresh keys on identity — delete-backfill posts no VoiceOver announcement
  • #2042 [focus][seam] DownloadController's shadow refresh drifted — vision single-flight bypassed, queued ⇧A never consumed
  • #2041 [data][focus] Background refreshFocused clobbers mid-edit drafts — date scrub snaps back and re-arms a stored-date write; title/caption flags silently disarm
  • #2016 [ux][receipts] Field-commit receipts can lie at the margins — stale-previous gate + success toast dropped on fast nav
  • #1935 [infra][robustness][deferred] Run the FULL FORCE_LEGACY non-init test pass on the push lane (init-crash + init-floor slices already shipped)

The full tracker is public: github.com/wells01440/taglens/issues. Beta feedback sent through TestFlight lands there too — screenshots welcome. The chatty part happens on the discussion board.

Send us your worst

The beta needs photos, and unlike every other photo product on earth, we especially want your bad ones. Blurry, crooked, thumb-in-frame, accidental ceiling, "why do I have eleven of these" — that's the good stuff. The reject loop and the low star bands get calibrated on exactly those, and the AI has to learn what mediocre looks like from somebody. Any photos help, honestly — gorgeous ones too, if you insist.

Send them through TestFlight feedback, or propose benchmark shots via the control-photo template. Only send photos you took yourself and are fine with us using as test material — rights rigor is absolute here, even for the blurry ones.

Thank you

Beta testers whose reports made the app better:

Want on this list? Break something and tell us how. Famous public-domain photos make great test subjects — see the control-photo submission template.