Changelog
What shipped, entry by entry.
Straight from the build log: each entry names what was built, what the test showed and what was left out.
2026-10-14 — Track M, phase M1.1: the product moves to labelchaser.ai (PROMPT-DOMAIN)
- Pull request from
track-m1-1-domain:a8e7c12(the move), then this record; merged tomainand fast-forwarded toreleaseafter the checks below. No migration, no dependency. Worker change (the app URL default inapps/worker/src/env.ts):releasedeploys it. - Built:
apps/web/src/lib/hosts.ts(the hosts fromNEXT_PUBLIC_SITE_HOSTandNEXT_PUBLIC_APP_HOST, defaultslabelchaser.aiandapp.labelchaser.ai;hostKind,routeFor,appHref,siteHref); the proxy routes by host through it (x-forwarded-hostfirst);lib/site.tsreads the site origin from it,LEGAL_OWNER_LINEwith the comment that one edit flips it,SIGN_IN_HREFandSTART_FREE_HREFon the app host,CONTACT_EMAIL=hello@labelchaser.ai; the header's Sign in, the app footer's Terms, Privacy and Status cross hosts; the cookie dialog and the status page name the host; emails and the worker link tohttps://app.labelchaser.aiunlessAPP_URLsays otherwise;docs/SETUP-STATUS.mdlists every console entry and the new environment variables (NEXT_PUBLIC_SITE_HOST,NEXT_PUBLIC_APP_HOST,APP_URL,RESEND_API_KEY,NOTIFY_FROM=LabelChaser <notify@labelchaser.ai>,CRON_SECRET); the site spec and the build plan name the new hosts. - Checked on the dev server with the Host header, signed out:
labelchaser.co/pricing→ 308https://labelchaser.ai/pricing;www.labelchaser.co/legal/privacy?x=1→ 308 with the path and query kept;www.labelchaser.ai/→ 308 apex;labelchaser.aiserves/,/pricingand/api/health(200) and sends/library,/login?intent=startand/auth/callbackto the app host (307);app.labelchaser.ai/and/start→ the site (307),/library→/login?next=%2Flibrary,/login200,/pricingand/sitemap.xml→ the site host;localhostandlabelchaser.vercel.appbehave as before. The sitemap listshttps://labelchaser.ai/…, robots points at it,/contactand/legal/dmcashowhello@labelchaser.ai, the footer shows the legal line. Tests: web 43 (+7 inhosts.test.ts, one of them scanning the web app and the legal content for the old domain), core 113, worker 6, model 23, providers 62; typecheck clean. - Not verifiable from here until DNS and the consoles exist: the live hosts, sign-in on the app host, the Dropbox connect round-trip; the report lists each console string, the Vercel domain steps and the DNS records.
- Housekeeping: twenty-four stray Finder-style copies (
… 2.tsx,… 2.png,0025_builds 2.sql) that appeared untracked in the checkout on Oct 14 broke the typecheck onceOWNER_LINEwas renamed; moved, not deleted, to../labelchaser-stray-copies-2026-10-14/.
2026-10-14 — Pilot fixes 4–8: orientation, save speed, Phase, confirm before spending, the first screen (PROMPT-PILOT-FIXES)
- Pull request from
pilot-fixes-2(stacked onpilot-fixes-1):f90f032(the fixes), then this record; merged tomainand fast-forwarded toreleaseafter the checks below. No migration, no dependency. Worker change (photo orientation, probe rotation):releasedeploys it, and a read pass on LabelChaser Test on Fly follows per the checklist. - Built:
readExifreads the Orientation flag and a photo is turned upright (auto-rotation off, the matching transpose) before its thumbnail and model image; a clip's rotate tag or display matrix is left to ffmpeg's auto-rotation, which the worker's ffmpeg applies to the still, the proxy and the motion stream and strips from the proxy, and the probe recordsrotationand the display size (motion document, assets width and height).saveToLibraryloads the run alone and runs its two statements together, loggingreview.savedwith the milliseconds; "Save N names · no credits" is busy from the click ("Saving N names…"). Step 3 shows Phase only where the client has a phase, with one sentence. Chase Labels asks once, "Chase N files for X credits?", with the folder count when several are ticked; Cancel starts nothing; the Chase button cannot be skipped by Enter. Start here shows a new member one card, the next step with its button, the three steps small underneath and "How LabelChaser works" folded; the full page returns once the three are done. - Checked: the sideways-clip test (ffmpeg on PATH) probes a clip carrying a −90° display matrix as 180×320 with rotation 90 and gets a portrait still and a portrait proxy with no matrix; the EXIF test reads orientation 6 and 8 and ignores 9; on the live pipeline (local worker code, a generated sideways clip) the probe reports the display size and the proxy comes out 406×720 without a matrix. Save, measured: the 73-label update of Jeff's run
7964cf4atakes 337 ms plus 44 ms for the run inside a rolled-back transaction; the lean action saved run8f01d998(2 labels) in 608 ms on the dev server, against 1,132 ms before, with a 1.4 s Library landing. Step 3: an unlinked LabelChaser Test folder under Cypress Site Solutions (no phases) posts a hidden empty phase and shows Client and Project only; the Day 1 folder (LabelChaser Test has a phase) shows the field with the sentence. Chase Labels on Day 1 opened "Chase 2 files for 2 credits?" and Cancel left no run. Tests: core 113, web 43, worker 6 (+3: the turn from a rotate tag or matrix, the filter maps, the sideways clip), model 23, providers 62; typecheck clean. - Not verified: Delin's own clip (not on this machine); if it carried no rotation metadata, a manual rotate on review is the follow-up. Screenshots (fixture):
docs/design/screenshots/2026-10-14-pilot-start-first-screen.png,…-pilot-start-first-screen-phone.png. - Logged, no code: the preset picker's one-line "use this when…" per preset (Kim).
2026-10-14 — Pilot fixes 1–3: the date override, validation before Preparing, Save row (PROMPT-PILOT-FIXES)
- Pull request from
pilot-fixes-1:5d608e2(the fixes), then this record; merged tomainand fast-forwarded toreleaseafter the done-when below. No migration, no dependency. Worker change:releasedeploys it, and a read pass on LabelChaser Test on Fly follows per the checklist. - Found (item 1): Delin's run
612b42b4(and its two twins45b4dd15,589bb92a, three clicks on Chase 11:11:06–:16 UTC) carriedrun:<id>:photo=2026-10-09_{project}_{setting}_{subject}_{framing}and the video twin: "Date for every file" wrote the day as a literal in front of the tokens, and the grammar requires{date}first (since Oct 7). All 50 items failed on parse before any model call (0 credits spent, 53.125 held each);maybeFinalizeparsed the same pattern, threw and rolled back, so the runs never left "running". Not a release change:releasemoved only by Tracks M1 and L1 between Oct 12 and Oct 14, and Jeff's Oct 12 run1e9efc4ehad no override rows (its names took the files' own dates). The override had never worked. - Built:
{date:2026-10-09}as the date token's fixed-date modifier (core parse and render; a reviewer's per-file date wins;{time}keeps the clock);packages/core/src/formula/chase.ts(pattern with date, kinds to validate, the one-sentence problem);startChaseresolves and validates the formulas before the run, the hold or a thumbnail exists; step 3 shows the fault; the worker's ingest checks again after listing and before Preparing;failRun(status failed, hold refunded when nothing was charged, stages closed) used by ingest and by finalize when every file failed; the Chase button busy while starting; Save row revalidates in place;lib/review-edit.tsas the pure row save; "Save row · no credits" as the one row button, "Save N names · no credits" in the bar. - Done-when on LabelChaser Test (local worker with this code, the Fly machine stopped): Day 1 (2 photos) with the override → run
8f01d998, review in 25 s, names2026-10-09_Nested_CommunityGrounds.jpg/…-2.jpg, 2 credits held and spent; Day 2 (1 photo, 1 clip) with the override → run7955c0ae, review in 41 s (preparing 17 s, labeling 22 s),2026-10-09_Dropbox_CommunityGrounds.jpgand2026-10-09_Dropbox_ExteriorFront_SodInstall_Tracking_01.mp4, 2.125 credits held and spent; both runs' formula rows read{date:2026-10-09}_…. Step 3 with{project}_{date}_{setting}: "The formula would fail every file, so no chase started and nothing was charged" and no run, hold or formula row written. Review on runfa29b11f: Place set to Yard on row 1 and Office on row 2, Save row on row 1 → row 1 reads Saved (database: setting Yard, accepted 15:12:27 UTC), row 2 still shows Office, the URL unchanged. Tests: core 112 (+6: the fixed date parses, renders, wins per file, a literal date still fails), web 43 (+8: the override on every preset renders one photo and one clip starting with the day; kinds to validate; the problem sentence; the movement save), worker 3; typecheck clean. - Still to do for Anthony: finalize Delin's three runs with the deployed worker (they end failed and refund 3 × 53.125 credits; the script was blocked from this machine); the twins show the triple-click the busy button now prevents. Five stray files named like
apps/web/src/app/sitemap 2.tsappeared untracked in the checkout on Oct 14 (Finder-style copies of M1 files); left alone, not committed.
2026-10-12 — Track L, phase L1: Studio › Project Builder (docs/STUDIO-PROJECT-BUILDER.md)
- Pull request from
track-l1-project-builder:b1b303b(the feature), then this record; merged tomainand fast-forwarded toreleaseafter the done-when below. Migration0025_builds.sqlapplied to the Supabase project (26 migrations). No new dependency. - Built:
buildsandbuild_items,runs.kindpush, RLS; the Studio rail group (Project Builder, Studio Tools muted "later"); Library checkboxes (32 px, on every grid tile and table row), "Select all on this page" and the selection bar ("4 selected · 3 photos, 1 video", Add to, the other drafts and "+ New build", Clear) with the toast "Added N files to " and Open Project Builder; /studio/project-builder(builds list with the current build marked, editable name, summary line, item grid, Remove, Duplicate build, Archive, the originals line, Push to Dropbox… / Push to Dropbox / Drive…; after a push Open folder, Share link disabled until L2, View under Changes, the destination path);/studio/project-builder/push(the connections the member can write through, the Chase picker with name search, new folder name, the project record, "12 copies · 3.4 GB · originals stay put · no credits", the clash list, Push N files; a reviewer sees it without a working button); the worker push job; Changes and the run page for push runs; the phone fallback ("Best on a larger screen", builds read-only); preview statesbuilder,builder-empty,builder-pushed,builder-reviewer,builder-none,push-dialog,push-picker,selection-bar. - Done-when on LabelChaser Test (Anthony's Dropbox, local worker with this code, the Fly machine stopped): build
229bd786"L1 push test" took two files from run995312ef(DSC03325.jpg,C2461.MP4inLabelChaser Test/) and two from run642167c2(DSC03321.jpg,C2461.MP4inDay 2/); the dialog listed the clashC2461.MP4 → C2461_2.MP4and the summary "4 copies · 272.1 MB · originals stay put · no credits"; the push ran as run8c03dea7(kind push, queued 11:14:04 UTC, done 11:14:16 UTC): folder/Anthony Seling/LabelChaser Test/L1 push testcreated (id:1B5cIMV3GNUAAAAAAAClXw), 4 journal rows applied with provider revs, Dropbox lists the four copies (134,494,169 B ×2, 1,812,253 B, 1,300,257 B); the four originals keep their names and paths; 4assetsrows withduplicate_ofon the new project node; project "L1 push test" created under LabelChaser Test withdate_shot2026-10-01 and a journal create row naming the build;node_foldersrole labelchaser → binding role delivery, display path/Anthony Seling/LabelChaser Test/L1 push test;run_metricsfinishing 4 of 4; credit entries for the run: 0; the builder shows "Pushed Oct 12 · 4 copies · 0 credits"; Changes shows "Push · 4 copies · 0 credits" with Open in Dropbox and Open the build (before the per-run journal fix it read "0 copies": a latent cap on the page, now gone). Reviewer: no reviewer account exists yet (Round 5's open item), so the role is covered by the roles test (can("reviewer", "push")false), thebuilder-reviewerpreview (Push disabled with "Pushing a build needs the member role or above.") and thepushBuildguard. - Suite: core 106, model 23, providers 62, web 35 (builds-shared rules and the role additions), worker 3; typecheck clean. Screenshots (fixture previews at 1,360 px; the signed-in screens were read in the pane and the outcome read back from the database and Dropbox, since the session cookie may not be exported on this machine):
docs/design/screenshots/2026-10-12-l1-builder.png,…-l1-builder-pushed.png,…-l1-builder-reviewer.png,…-l1-push-dialog.png,…-l1-push-picker.png,…-l1-selection-bar.png. - Defaults to veto: "Untitled build" and "
copy" as names; "Share link" present but disabled until L2; the Studio Tools note "later"; run_itemsrows for a push; reviewers creating and archiving drafts. Not in this phase: share links and saved-filter sources (L2), pushed folders that refresh. Production pushes need the worker from this commit: the fast-forward ofreleasedeploys it; until then a push queued in production would be read by the old worker and fail as "not a write run".
2026-10-12 — Track M, phase M1: labelchaser.co shell, home and first-pass pages (docs/SITE-HEADER-FOOTER.md)
- Pull request from
track-m1-site-shell:11a909e(the site), then this record; merged tomainand fast-forwarded toreleaseafter the done-when below. One dependency added:marked16.4.1 (Markdown for the legal pages and the changelog). - Built: the
(site)route group and layout;SiteHeader(Paper 64 px → Navy compact 52 px after 24 px of scroll, Wordmark · How it works · Features · Pricing · For you ▾ · Security · Sign in · Start free; under 900 px Wordmark · Start free · hamburger → full-screen drawer),SiteFooter(tagline, Product / Company / Legal, Status, "A Liquid Moth Venture", the owner line, Cookie choices),/(hero, demo card fromcontent/site/demo.json, proof strip, closing CTA), the first-pass pages/how-it-works,/features,/pricing(fromlib/pricing.ts),/security,/for/photographers,/for/videographers,/for/social-marketing-teams,/help,/about,/contact,/changelog(fromdocs/MILESTONES.mdat build),/statusand/api/health(app, Supabase round-trip, worker),/legal/terms,/legal/privacy,/legal/acceptable-use,/legal/dmca(fromapps/web/content/legal/*.md, placeholders until the texts exist; the Google Limited Use disclosure verbatim on Privacy),sitemap.xml,robots.txt, the 404 and 500 pages with the serval, metadata and Open Graph per page,/login?intent=startreading "Start free — 250 credits", the app shell's legal + status line, and the proxy guarding the app's routes by name (a signed-in visitor to/lands on/start). - Done-when: every header and footer link answered 200 on the dev server signed out (21 routes) and an unknown address answered 404 with the serval page; Lighthouse mobile on
/against the production build, two runs: performance 95, accessibility 100, best practices 100, SEO 100 (LCP 2.9 s simulated, CLS 0, TBT 20 ms); keyboard only: Tab reaches "For you", Enter opens the menu with focus on Photographers, ArrowDown moves to Videographers, Escape closes it and returns focus to the button; on a 375 px viewport Tab reaches the menu button, Enter opens the drawer with focus on Close and the page scroll locked, Escape closes it and returns focus to the button with scroll restored; the signed-in app is unchanged (the rail's three groups,/→/start, no console errors) apart from the one-line footer. - Owner line shipped, for Anthony to confirm against the Florida filing:
© 2026 Liquid Moth LLC d/b/a LabelChaser · Estero, Florida. - Suite: web 28 (site routes, metadata, legal placeholders added); typecheck clean; production build clean (42 static pages). Screenshots:
docs/design/screenshots/2026-10-12-m1-home.png,…-m1-phone-home.png,…-m1-phone-drawer.jpg,…-m1-pricing.png,…-m1-legal-privacy.png,…-m1-status.png,…-m1-404.png. - Defaults to veto: the contact address
hello@labelchaser.co; the legal publication date 2026-11-02; the pricing page naming the tiers without monthly figures (not in the repository); the demo card's third row as a sample graphic (the benchmark has none); the "A Liquid Moth Venture" line above the owner line. Not in this phase: host-based routing for labelchaser.co (one host until the domain points at Vercel), the consent bar (no optional cookie yet), the full M3 page layouts.
2026-10-12 — Round 5: team and first run (FEEDBACK round 5)
- Commits on
mainafter02e5e59:b759ba1(notifications: Resend transport, templates, the worker's review-ready email, the weekly digest on Vercel Cron and "Send me the digest now"),fdb5948(migration 0024; roles Owner / Member / Reviewer, invitations, deactivation, the allowed-domains setting, every write gated on the role),896c47d(connections per member, the "read through Anthony Seling's Dropbox" notice with "Connect your own", share with the workspace),e37d31a(first run on Start here and the hubs' empty states, the previews), then this record; fast-forwarded toreleaseafter this entry. - Migration
0024_team.sqlapplied (25 total):memberships.rolenow owner | member | reviewer (no admin rows existed),status+deactivated_at+invited_by,invitations,storage_connections.owner_user_id(both existing connections backfilled to Anthony),notifications;is_member,has_roleandmy_workspace_idscount active memberships only (read back: the function body checksstatus = 'active'); the sign-up trigger reads an open invitation first, then the workspace'ssignin_domainandsettings.allowed_domains. - Verified on the dev server against the one Supabase project, signed in as Anthony (owner): Account › Team lists Anthony Seling (Owner · Active · Oct 7 · 50 chases) and Delin Spahiu (Member · Active · Oct 11 · 2 chases) with the role select, Save and Deactivate on the other member; inviting
labelchaser-test@sunluxmedia.comas Reviewer recorded the invitation ("Reviewer · by Anthony Seling · no email sent", Record again, Revoke) and anotificationsrow (invite, skipped, "RESEND_API_KEY is not set"), then Revoke cleared it. "Send me the digest now" recorded the digest (weekly_digest, skipped) with the subject "LabelChaser week of 2026-10-05: 45 chases, 532.5 credits, 483 files renamed". Connections reads "anthony@sunluxmedia.com · connected by you" with "Share with the workspace" on both, and the mapped-folders table says "Your Dropbox" per row; Start here shows Connect storage · Pick a folder · Chase Labels all done for Anthony. The fixture preview renders a new member's Start here (step 1 next, Connect storage), the same after connecting (step 2 next), the run actions for a member (Review · Duplicate · Rename · Relabel · Archive) and a reviewer (Review · Relabel · "Renaming needs the member role or above"), and the connection notice with and without "Connect your own Dropbox". Memberships, connections, runs, labels and files unchanged; nothing written to storage. - Suite: core 106, model 23, providers 62, web 23, worker 3;
pnpm typecheckclean (10 of 10); production build clean (6 of 6). Screenshots:docs/design/screenshots/2026-10-12-r5-team.png,…-r5-phone-team.png,…-r5-start-new-member.png,…-r5-start-member-connected.png,…-r5-start-owner-done.png,…-r5-connection-notice.png,…-r5-run-actions-by-role.png,…-r5-connections.png,…-r5-account-notifications.png. - Not done here: the member walk-through of the done-when (a real second account signs in, connects their Dropbox, chases a
LabelChaser Testsubfolder, Anthony renames, Changes shows their name) needs the address Anthony supplies; the reviewer's screen is shown from the fixture and the role matrix is tested. No email goes out untilRESEND_API_KEYandNOTIFY_FROMare set on Vercel and Fly (plusCRON_SECRETon Vercel andAPP_URLif the origin ever changes); every attempt is recorded undernotificationsmeanwhile.
2026-10-12 — Round 4: hub usability and leftovers (FEEDBACK round 4)
- Commits on
mainafter822b18d:b7801db(migration 0023; Archive and Restore for formulas and runs with the Archived filter on the Runs log; the term-alias editor),51fdae0(carry by default with "leave them on the parent", the one-sentence toast with Put it back after reshape, move and associate, Move under…, the duplicate-name guard, the client card copy and chips, Rename client, the folder-name suggestion, phone sheets),a879059(alias hints in the prompts, the Review card's "+ ID Segment" from the run's formula), then this record; fast-forwarded toreleaseafter this entry. - The data, from the journal: at 00:51Z a second standalone "Uptown Chemist" program was created from the Programs hub, at 00:53Z the real client became a program under Kelly General Contracting (twice, a double submit), at 01:12Z Before Demo was moved into the duplicate. Fixed through the app as Anthony's user: Before Demo moved under Kelly General Contracting › Uptown Chemist (01:25:57Z, journal
565bd029), the duplicate5fbef31carchived (01:27:49Z), its "client of" link to KGC removed. After: the Programs hub shows one Uptown Chemist card (pharmacy · Preset: real-estate · 1 run · 55 files) with Before Demo - First Day - 10.9.26 · 55 files · shot 2026-10-09 · "Saved, not renamed →" and Move under…; the KGC card reads "Dropbox · 1 folder · last chased Oct 10", the Uptown Chemist chip, "Saved, not renamed →", 1 project · 1 run · 55 files · 61.875 credits. - Done-when on
LabelChaser Test(dev server against the one Supabase project, signed in as Anthony): "Change client to… → Program under Nested" landed on/programs/LabelChaser-Testwith the toast "LabelChaser Test is now a program under Nested · 1 program, 5 projects, 10 folders and 92 files came along" and Put it back on it; Put it back landed on/clients/LabelChaser-Testwith "Put back · LabelChaser Test is now a client · 1 program, 5 projects, 10 folders and 92 files came along" (journal28ae4435then7453a639). The same with "Leave its 1 program, 4 projects on Nested" ticked: the toast read "… · 1 program and 4 projects stayed on Nested", the Nested client page listed Dropbox, Nestd, Week 4, Zero Changes and Site documentation with Move under… on each, the journal held the reshape, five child reshapes and acarryrow (left); Put it back moved all five back and wrote acarryrow (back); the tree read as before. "Move under…" on the Projects table put Zero Changes under Site documentation ("Zero Changes now sits under Site documentation · 1 folder and 12 files came along") and back. "Associate to…" on Zero Changes landed on its page with "Zero Changes is now associated with Cypress Site Solutions (related)"; Put it back unlinked it. "Rename client" from the card menu renamed Nested → Nested Test → Nested; the Day 2 project's Edit tab suggested "Nested" from its folder. node_folders stayed at 15, runs 89, labels 1,159, renamed files 7; nothing written to storage. - Test records archived on production (item 4), each through the app and journaled: the Nested project moved back under LabelChaser Test ("Nested now sits under LabelChaser Test · 4 folders and 6 files came along"), the Site documentation program archived (01:59:53Z), the "Site work (Sunlux)" default for LabelChaser Test removed (an
editrow on the client with the formula ids) and the formula archived (02:00:30Z; it sits under "Archived (1)" with Restore and the chain skips it), the six test chasesf6ab33e9,fb06d5b8,2d7ce19f,9482ee09,dd6bd914,882fcf54archived from the Runs log (sixarchive_runrows; their labels stay: 2, 1, 2, 2, 2, 2). The Programs hub's Active view lists Uptown Chemist alone; the Clients hub keeps LabelChaser Test, Cypress Site Solutions and Kelly General Contracting. Journal rows 32 → 45 over the round. - Phone pass at 375 px (headless Chrome): Clients, Programs, Projects, Formulas and the two dialogs; cards stack, the Programs card shows one thumbnail, the Projects and ID segments tables scroll in their box, dialogs are full-height sheets.
- Suite: core 102, model 23, providers 59, web 20, worker 3;
pnpm typecheckclean (10 of 10); production build clean (6 of 6). Migration0023_archive_formulas_runs.sqlapplied (24 total). Screenshots:docs/design/screenshots/2026-10-11-r4-before-programs-uptown.jpg,…-r4-before-clients-kgc.jpg,…-r4-after-programs-uptown.png,…-r4-after-clients-kgc.png,…-r4-dialog-change.png,…-r4-dialog-move.png,…-r4-toast-put-it-back.png,…-r4-phone-clients.png,…-r4-phone-programs.png,…-r4-phone-projects.png,…-r4-phone-formulas.png,…-r4-phone-dialog-change.png,…-r4-phone-dialog-associate.png. - Not in this round: a journal table for formulas (a formula's archive is on its row); the Nested project's test location "Naples, FL" from phase 2 is still set.
2026-10-12 — Track K phase 3: the Formulas page and the vocabularies (docs/HUBS-MODEL.md)
- Commits on
mainafter69d1c8d:2ba3545(taxonomy 2.2 into vocabularies and terms, the term overlay in the model package, the worker reading a run's formula vocabulary),966fa03(the Review, Change for all and Chase Labels on formulas and vocabularies, defaults resolved project → program → client → workspace with the reason line,runs.formula_ref),f7a11a8(the Formulas page), then this record; each fast-forwarded torelease. CI green on both branches; deploy-worker green at 00:08Z; Vercel Ready. - Vocabularies: migration 0020, generated from the taxonomy, made 20 preset vocabularies (one per model-picked segment per preset formula) and their terms; a check script compared every list with the taxonomy: 20 of 20 equal. Presets stay read-only records; Duplicate copies the formula, segments, vocabularies and terms into editable workspace rows. The model's prompt parity tests are unchanged (model 22, worker 3) and the new round-trip test shows a preset's own lists give back the same vocabulary, so the worker's prompts, schemas and pass 2 are what they were.
- Formulas page
/formulas: Your formulas (presets marked read-only, custom below) and Used by default for with "+ Add a default" (client, program, project or the workspace) on the left; the selected formula's photo, video and graphic patterns as ID segment chips in the seven colours with drag to reorder and "+ ID Segment" (vocabulary-backed segments and fixed text), a sample rendered from the workspace's latest labeled photo and video, the ID segments table (name, source, term count, note, Edit terms, Settings) and Terms for the chosen segment with add (single or pasted list), rename, merge selected, retire and restore, and a search once the list passes 30. Buttons by tier; the breadcrumb is the only text link. Formulas is live in the rail. - Hooks: the Review editors, "+ ID Segment", Change for all, the Library's Change for all and Chase step 3 read the run's formula and vocabularies; a retired term is not offered and stays on names; a renamed or merged term updates proposals of runs still in review that use the formula and never a saved name or file. Chase step 3 lists every formula, picks the default by the chain and says why ("Site work (Sunlux), from client LabelChaser Test").
- Done-when on
LabelChaser Test: Site work duplicated as "Site work (Sunlux)"; on its Place terms, Yard added, Parking retired, Jobsite renamed Worksite; the duplicate set as the default for the LabelChaser Test client ("Used by default for: LabelChaser Test · client"). Chase Labels onNested/Day 1picked it with the reason line; the chase before the worker deploy (dd6bd914, 2 credits) still labeled Jobsite from the old image, and its Review editor offered Street, Worksite, Entrance, Interior and Yard (Parking and Jobsite absent). After the deploy, chase882fcf54(2 credits; wake 0.2 s on a running machine, listing 2.0 s, preparing 2.3 s, labeling 5.6 s) proposed2026-10-01_Nested_Worksite_SodInstall.jpg; renaming Worksite to Site on the Formulas page updated both proposals in review to2026-10-01_Nested_Site_SodInstall.jpgand nothing else. The preset snapshot (patterns, segments, active and retired terms of all seven presets) hashed56c0e00e…7932e29before the duplicate and again after every edit: byte-for-byte unchanged. Older runs, labels and the seven renamed files are unchanged; nothing was written to storage. - Suite: core 102, model 22, providers 59, web 11, worker 3; typecheck clean; production build clean. Screenshots (fixtures, 1200 px):
docs/design/screenshots/2026-10-11-k3-formulas-preset.png,…-k3-formulas-custom.png. - Not in this phase: term aliases are stored but not edited on the page; the Review card's "+ ID Segment" still lists the fixed token set rather than reading the formula's segments; the LabelChaser Test default and the "Site work (Sunlux)" copy are test records Anthony may keep or remove.
2026-10-11 — Track K phase 2: Programs and Projects (docs/HUBS-MODEL.md)
- Commits on
mainafter638a049: the segment tokens, the thumbnail route and the meta row; the Programs and Projects hubs with their pages and the shared view; the Runs meta row, the Chase program select, the preview and this record; fast-forwarded toreleaseafter this entry. - Programs hub
/programs: a 60/40 card per program (name, description, default-formula chip, cadence, runs and files; Clients as chips with "+ Link a client"; Projects as rows with files, status and Open, "+ New project" and "Link a project"; Open program · Change program to… · Associate to…; two provider thumbnails and the project links on the right); search, Client and Formula filters; "+ New program" in the header. Projects hub/projects: the table (Project with run count, Client, Program chip, Date shot and Location edited in place, Files, Status, Review or Open) with a gallery row of six provider thumbnails and "All files →" into the Library filtered to the project; Client, Program and Status filters and search. Program and project pages share the Client page's view with the tabs that apply; a project page carries the meta row and its files. - Rail: Programs and Projects live; Formulas still muted. The seven ID segment tokens shipped (setting Serval Tan); the Review card and the Chase sample took them with no other change.
- Done-when on
LabelChaser Test: the Projects table listed the ten backfilled projects with their dates (Before Demo 2026-10-09, Aubri Montini 2026-10-02, the LabelChaser Test projects 2026-10-01, 117 Wading Bird 2026-05-09, 5791 Harborage 2025-07-29) and six-thumbnail galleries; "+ New program" made Site documentation under LabelChaser Test; "Change project to…" on Nested with "Keep it a project, just move it" placed it under the program, and the Programs hub card then read "Site documentation · per site visit · Preset: real-estate · 15 runs · 6 files · Clients: LabelChaser Test · Projects: Nested · 6 files · shot 2026-10-01 · Ready to save" with two live thumbnails; "Add location" on the Projects table saved Naples, FL and the Runs card for Day 1 read "LabelChaser Test › Site documentation · 2026-10-01 · Naples, FL", as did the project page's header. Read-only on production: Before Demo - First Day - 10.9.26 lists under Uptown Chemist with 2026-10-09 and "16 to review"; the Program chip appears once Anthony reshapes Uptown Chemist. 5791 Harborage was attached to LabelChaser Test from its project page ("LabelChaser Test · 2025-07-29") and put back ("No client · 2025-07-29"); both steps are in the journal. Chase Labels onNested/Day 1showed the Program select prefilled with Site documentation from the folder's program. Runs 87, labels 1,155, journal rows 1,871 and the 7 renamed files unchanged; nothing written to storage. - Suite: core 102, model 20, providers 59, web 9, worker 3; typecheck clean; production build clean. Screenshots (fixtures, 1200 px):
docs/design/screenshots/2026-10-11-k2-programs-hub.png,…-k2-projects-hub.png,…-k2-project-page.png. - Not in this phase: the Formulas page (phase 3) and the program's default formula beyond the chip and the Edit select; Library thumbnails stay the stored ones.
2026-10-11 — Track K phase 1: the hub model, the Clients hub, the Client page, the two dialogs (docs/HUBS-MODEL.md draft 2)
- Migrations
0017_hubs.sql(the hub columns onnodes,node_profiles,node_logos,node_people,associations,node_folders,node_journal,runs.project_id,formulas,formula_segments,vocabularies,vocabulary_terms,formula_defaults, RLS as today's member rules,reshape_node(), the backfill),0018(the two kit presets),0019(segment order), all applied to the one Supabase project. Backfill: 5 clients and 10 projects shaped from the mapping rows, 15 mapped folders linked as sub folders, 86 of 86 runs given a project, 10 projects a date shot, 7 presets as formulas rows with 4–7 segments each. Nothing deleted; the only rows removed in the whole phase were the derived segment rows rebuilt by 0019. - Rail in three groups (Work · Organize · Settings), Clients live, Programs · Projects · Formulas muted until their phases. Six button tiers in
tokens.jsonandButton/ButtonLink(tier,size), used throughout the hubs. - Clients hub
/clients: five cards from the backfill (Anthony Seling · Client Master Folder - Active Clients · LabelChaser Test · Nested · Raw Videos), each with the logo tile, name, tagline, Chase Labels top right, program chips, the review count as a review-tier button ("16 to review →", "4 to review →", "Ready to save →"), the stats line ("1 project · 1 run · 55 files · 61.875 credits"), the mapped folder, then Change client to… · Associate to… · Open client; search, Program, Status and Sort filters; + New client and Import from folders in the header. - Client page
/clients/[slug]: header with the logo tiles (up to five), status, Change client to…, Associate to…, Edit client, Chase Labels; tabs Overview · Folders · Programs & projects · Branding · Online & social · Tags & people; the Overview as mocked (Description with Edit, Folders mapped in the four roles with Open and Chase per folder and an add form per role, Programs and projects with Open and + New / Associate, Recent runs; Branding, Online & social, Caption tags, Profile tags & collaborators, Associations on the right). - Done-when, on production data: the Sony S3 shoot's path-guessed client "Raw Videos" was renamed Uptown Chemist (kind pharmacy) through Edit client; "Change client to…" with Program and "Under a new one: Kelly General Contracting" reshaped it in one journaled call: the hub then showed Kelly General Contracting with the Uptown Chemist chip, "16 to review →", 1 project · 1 run · 55 files · 61.875 credits and the Sony S3 folder; the KGC page listed the program and the project with their Review buttons and the folder. "Associate to…" from the KGC header with "+ New Cypress Site Solutions · contractor" made the client and the link; both pages show it. "Put it back" from the banner reversed the reshape; the tree reads Uptown Chemist › Before Demo - First Day - 10.9.26 › Sony S3 again, with Kelly General Contracting and Cypress Site Solutions standing as clients. Through all of it the Sony run kept its project, its 55 labels, its 55 proposed names and its 55 journal rows;
node_foldersstayed at 15; no file, run or name changed. The Change dialog also opens from a hub card. Journal: edit, create, reshape, create, reshape. - Chase Labels prefill: picking
Nested/Day 2/Droneshowed "Client from the hub: LabelChaser Test, project Dropbox" with "Linked to LabelChaser Test" under the Client field; a folder without a link keeps the path guess and says the chase creates the client and project. New mappings give their nodes a shape and link the folder. - Suite: core 102, model 20, providers 59, web 7 (the tree helpers), worker 3; typecheck clean; production build clean. Screenshots (fixtures, 1200 px):
docs/design/screenshots/2026-10-11-k1-clients-hub.png,…-k1-client-page.png,…-k1-dialog-change.png,…-k1-dialog-associate.png. - Not in this phase: Programs, Projects and Formulas pages (phases 2 and 3); vocabularies and terms for the preset formulas; the §4 ID segment palette (its amber clashes with the review band, DECISIONS).
2026-10-11 — Feedback round 3, Track J: the Review card, Fix one value everywhere, Review as the next step, Runs as a log, Changes, Chase Labels, the tokens
- Commits on
main:dd61a31(J1 the card and J2 the two cards with the sticky bar),371316a(J3),1da4ae3(J4, no meta row),1dac01c(J7 tokens),f2a9d21(J5 "Changes"),3954945(J6), then the preview route, the card extraction and the screenshots; fast-forwarded toreleaseafter this entry. - Bug found first: the Movement chips were display-only (DECISIONS); replaced by the Movement editor and quick picks.
- J1–J3 on
LabelChaser Test: chasefb06d5b8ofNested/Day 2/Drone(1 clip, site-work preset, 1.125 credits; wake 2.1 s, listing 2.3 s, preparing 15.8 s, labeling 18.6 s) came back with one NEEDSREVIEW clip,2026-10-01_Day-2_Jobsite_SodInstall_NEEDSREVIEW_01.mp4. The card showed the amber band on{movement}and the Movement editor, "Needs review: movement. Pick or type the value below."; the Tilt-Up quick pick re-rendered the name to…_Tilt-Up_01.mp4live with "Save row" enabled; saved → "Saved", Accepted, 90 % confident, the bar at "0 to review · 1 confident · 1 name". Fix one value everywhere, Place Jobsite → Yard: "1 file is labeled Jobsite. Change them all to:", "Apply to 1 file" → "Changed 1 file.", name…_Yard_SodInstall_Tilt-Up_01.mp4. "+ segment" with fixed text Drone →…_01_Drone.mp4, the formula line ends_Drone, toast "Added Drone to every name in this run". The run page shows the chip "1 to review", the banner's green "Review 1 name" and the same button above the table; Duplicate and Rename secondary. Nothing was written to Dropbox; the run stays in review. - What Anthony will see, read-only: Sony S3
7787c8a7→ "Review 55 proposed names · 39 confident · 16 to review · 0 low", the bar "16 to review · 39 confident · 55 names" with "Save 55 names", the Needs review filter at 16, Fix one value opening on Room with "Closet · 12 files" (then Office 9, Foyer 8, Hallway 7…), the first cardC2647.MP4→2026-10-09_Before-Demo-First-Day-10-9-26_Hallway_Contractors_NEEDSREVIEW_01.mp4with the amber band on movement (measured · 0.63) and the quick picks under it; the run page's button reads "Review 16 names". Aubri Montini568ee244→ "Review 47 proposed names · 43 confident · 3 to review · 1 low", the bar "4 to review · 43 confident · 47 names", Fix one value on Room with "Bedroom · 13 files" (Kitchen-Living 5, LivingRoom 4, Bath 4…), the first cardDSC02335.jpg→2026-10-02_Aubri-Montini-Real-Estate-Photos_NEEDSREVIEW_Lighting_Detail.jpgwith the amber band on the room; the run page's button reads "Review 4 names". Neither run was changed; the round-2 Change for all previews were never persisted (a preview is computed on request), so there is nothing staged to lose, and the controls are where they were. - Runs: 47 chases as cards with thumbnails, writes grouped ("4 renames · last 12:06 PM" under Day 2, "2 renames · 1 duplicate · last 2:34 PM" under the gate folder), the status, provider and member filters and the search;
?status=reviewlists 33. Chase Labels: tiles 191 × 106 px; a Dropbox search for "Day 2" returned 20 hits with paths (Day 2, Day 1, Before Demo - First Day - 10.9.26 as folders with Open · Pick; files with Pick its folder); the Formula step as six sub-cards with the sample in the Review colours. - Screenshots (fixtures, 1200 px):
docs/design/screenshots/2026-10-11-j1-review-card.png,2026-10-11-j4-runs-card.png,2026-10-11-j6-chase-step-1.png. - Suite: core 102, model 20, providers 59, web 3, worker 3; typecheck clean across 10 packages; production build clean.
- Plan change implied: none for Track J; Track K (hubs, Formula page) waits for the model and mockups.
2026-10-11 — Feedback round 2: name parts editable before the chase (I1), Change for all (I2), a new rename for a renamed run (I3), and the idle-exit race
- Commit: the round-2 commit on
mainaftera5cc490(I1, I2, I3 and the race fix), fast-forwarded torelease. - I1 on the Chase Labels page, Dropbox
LabelChaser Test/Nested: the mapping step's sample followed every keystroke: "Nestd" typed as the project showed2026-10-01_Nestd_…, a date override2026-10-09moved the date in the sample, a custom pattern…_{setting}_{subject}_01.jpgrendered with placeholders, a preset switch refilled the pattern; the project was corrected to "Nested" before the click. Chase Afa29b11f(Day 1, 2 photos): wakestarted: 1in 10.7 s, listing 1.4 s, preparing 2.3 s, labeling 4.7 s, 2 credits; names2026-10-01_Nested_Jobsite_SodInstall.jpgand…_SodInstall-2.jpg. No per-run formula row was written because the pattern equalled the preset (a first cut wrote one anyway; fixed). - I2 on chase B
995312ef(Day 2, 1 photo and 1 clip, chased with the bad project "Nestd" kept, 2.125 credits): Change for all, project → "Nested": preview "2 of 2 files affected" with the current → before → after rows, apply → toast "Changed 2 files.", names2026-10-01_Nested_Jobsite_SodInstall.jpgand2026-10-01_Nested_Jobsite_SodInstall_Push_01.mp4, the edit journaled on each label, no credits. The first cut confirmed the whole row (a NEEDSREVIEW clip on the Sony run turned intoPan-Leftin the preview); fixed withedited_partsand re-checked: NEEDSREVIEW stays. - Saved ("Save 2 names to library"), then renamed: write run
5eed08bequeued 15:48:20.8Z with its 2 journal rows planned first. It sat in Queued: the worker's idle exit fired at 15:48:22.7Z, 180 s after chase B's last work and 1.9 s after the job was queued, and the wake call had found the machinestarted. Caught by the poll and fixed as DECISIONS records; the fixed run page's nudge at 16:00:37Z started the machine (worker.nudge started: 1, 2.3 s), Flystarted16:00:38.7Z, run done 16:00:43.8Z, 2 applied. Undoa5179e33: queued 16:01:20.2Z, done 16:01:26.3Z, 2 restored; Dropbox listedC2461.MP4andDSC03321.jpgagain (modified 16:01:24–25Z). - I3 on the same run (Done, renamed before): project → "Nested" (after a "NestedTwo" round that exposed the detection bug: the first cut looked for applied rows on the read run and went back to Review with the bulk toast). Preview "2 of 2 files affected · names were pushed before: applying opens a new rename to confirm, undoable any time", button "Change 2 names and prepare the rename", apply → the write page with "2 names changed. Confirm below to push them; undo is available any time." and "2 files renamed, 0 already named · 0 credits"; rename
13d38f28queued 16:05:07.0Z (the machine had stopped at 180 s again; a normal wake, Flystarted16:05:10Z), done 16:05:14.9Z, 2 applied; undo1104d39016:05:56.9Z → 16:06:01.2Z, 2 restored and the rename's rowsreverted; Dropbox lists the camera names (modified 16:05:59–16:06:00Z). Every write had its journal row first; nothing deleted; 0 credits for the whole chain after the two chases. - Previews on the real runs, nothing applied (Anthony applies and renames himself): Sony S3
7787c8a7, project → "UptownChemist": "55 of 55 files affected", no new clash,2026-10-09_Before-Demo-First-Day-10-9-26_Closet_SafeDepositBoxes_Push_06.mp4 → 2026-10-09_UptownChemist_Closet_SafeDepositBoxes_Push_06.mp4, the NEEDSREVIEW clip keeps NEEDSREVIEW. Aubri Montini568ee244, find " Real Estate Photos" replace with nothing: "47 of 47 files affected", no new clash,2026-10-02_Aubri-Montini-Real-Estate-Photos_PrimaryBath.jpg → 2026-10-02_Aubri-Montini_PrimaryBath.jpg, the existing-2/-3suffixes stay. The Library filtered to the Sony run (/library?run=7787c8a7…) shows 55 files, the run chip and the same control. - Not re-verified in the browser: the sample's message for an invalid pattern (the server rejects such a pattern with
error=patterneither way). Not built: the optional "Re-read this part" model action. - Suite: core 99, model 20, providers 57, worker 3; typecheck clean across 10 packages; production build clean.
- Plan change implied: none. Anthony's steps: apply the two previews and click Rename himself; the Day 2 test copies stay his to clear.
- Release:
72d7d15fast-forwarded toreleaseat 16:18Z; CI green onmainandrelease, deploy-worker green at 16:19:44Z (the deploy updated the stopped machine to the new image and left it stopped), Vercel production Ready (22 s build,labelchaser.vercel.applogin 200). Post-deploy chasef6ab33e9(Day 1, 2 photos, real-estate preset) from the local page: wake 1.8 s (started: 1), Flystarted16:20:41.0Z, first touch 16:20:41.8Z (3.3 s from run created), listing 2.3 s, preparing 2.1 s, labeling 4.1 s, finishing under 0.1 s, 2 credits, in review; the machine exited 0 on its own at 16:23:53Z (184 s after its last work;requested_stop false,oom_killed false), so the queue-depth check before the idle exit did not keep it up. The sample's invalid-pattern messages were checked on the way: "Unknown token "{nope}" at position 17." and "Unclosed "{" at position 7.", and the name again once fixed.