The toolbox, and four new pieces: travel, Ceremony, Boxes and the Bar - #20
Conversation
The "Modular Workspace" PRD read against the suite, with the maintainer's answers recorded as decisions. Most of what it asked for exists: one document, local-first storage, lazy tools, and Timeline's double-booking check. What is new is a way to add and remove tools, travel time and calendar files on the Timeline, a Ceremony tool sharing Group shots' people, a Boxes tool tied to the day, and a UK-first bar calculator. Two findings shape it: a slice the contract does not list merges local-over-server with no conflict, so every new slice goes into SLICE_NAMES; and 144 KB of the 522 KB every page loads is fontkit, reached statically from the store. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
The five stay on by default and any can be removed; the choice lives in a new contract slice, `tools`, so a partner and a planner see the same set and it merges as a part of its own rather than conflicting with the date. A removed tool is hidden, never deleted: its tab, its front-page area, What is left's items for it (in `readiness` itself, so the planner's Weddings page agrees), its tour chapter and its palette entry go, and adding it back brings its work back as it was. Add and Remove are one labelled step each on the wedding's history. The header ends the tabs with +, opening Tools as a slide-over at the right edge, addressable as ?panel=tools. Sync & history's addressing moved into one factory both panels use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
The header now reads Guests, then the wedding's tools, then +. Guests is never removable: every tool is built on the guest list. Money, Checklist and Binder are tools like the five, off until a wedding adds them, and the menu under the wedding's name keeps only Overview. A tool not shown, removed or never added, is out of the header, the front page, What is left, the tour and the palette alike. With every tool added, the header at 1024px gave the tabs 392px and left Timeline 244 of the 323 its controls need, putting four out of sight. The tool on screen now keeps its controls and the tabs scroll instead, which holds as more tools arrive. The example wedding shows every tool, held there by a test, so the tour and front page can still point at all of it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
fontkit, 144 KB gzipped, loaded on every page of the app, the checklist and the money page included. Traced by static imports: the shared store syncs Place cards' assets, which reads the card design, which starts from Place cards' template defaults, which imported one four-field constant, DEFAULT_FIT, from the module that measures text with fontkit. DEFAULT_FIT now lives with the other template defaults, and nothing outside Place cards reaches the measurer. Measured on a production build, each route loaded in Chromium: the JavaScript every page shares went from 522 KB to 393 KB gzipped, and the front page's own from 40 KB to 17 KB. Place cards now carries fontkit itself, which it needs. A test walks the static imports from both layouts and names the chain if the engine becomes reachable again; it fails with the old import put back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
The guard added in the last commit used the `s` flag, which TypeScript rejects below ES2018, the suite's target: typecheck failed while the test itself passed. The flag did nothing — `[^;]` already crosses lines — so it goes. The guard still fails with the old import put back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
Travel. The couple types how long it takes to get between two places, in a new Travel panel listing exactly the pairs the day moves between; a blank is never checked. A new advisory, no-travel-time, says when somebody is due somewhere before they could get there: "Eleanor Vane Photography finishes Ceremony at 14:15 at Orangery, and is due at Confetti at 14:15 at Front steps, 5 minutes away: 5 minutes short." Who moves is a tag, as the double-booking check already reads it, not a lane: the example's Suppliers lane holds the florist, the caterer and the band. Measured from where the run sheet says a block ends, before its contingency buffer; an overlap is left to the double-booking check. Calendars. The whole day, or one tag's blocks, downloads as .ics (RFC 5545: CRLF, folded at 75 octets without splitting a character, escaped, stable per-wedding UIDs). Times are the venue's clock with no zone, on the wedding's own date, and refused without one: the timeline's date is a placeholder until one is set, and its UTC offset reads as British Summer Time until somebody chooses otherwise, which would put a winter wedding an hour out in UTC. Money's whole-number-or-nothing input moved to the kit as WholeNumberInput, and both pages use it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
Reproduced first, in a test kept as the regression: a wedding with no UTC offset, one block added in Timeline, and the wedding's event said 60. The timeline filled a missing offset with British Summer Time, and writeSlice echoes the offset into the event on every edit, so any Timeline change made the guess the wedding's clocks. The Day panel then showed it as chosen, choosing it again changed nothing, and the Binder trusted it over the phone's own clock. The offset is now null until somebody chooses it: in Cadence's day, the contract's published day, and Delegation's reader, with no fallback. The Day panel offers "Not set", so any choice is a change; sunset and the golden-hour advisory wait for the clocks rather than being worked out an hour out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
The calendar's comment justified local times by the Day panel showing British Summer Time until set, which is no longer so. The reason stands on its own: an offset may not be set, and the venue's clock is the one read on the day. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
The couple, their parents, their wedding parties and roles of their own devising move out of the group shots into a `cast` slice, because Ceremony is about to edit them too and a tool writes only its own slice. Each partner's grandparents join the fixed roles, as a party role. Moved by the load-time pass that already converts "bride" and "groom", silently and in one write with the shots it leaves. Read from either place until then: the planner's Weddings page runs What is left over stored documents on the server, and a wedding nobody has opened since must not read as having no cast. The validator reads it the same way. Group shots' "Who's who" now edits the cast; its list, prints, the front page, What is left, the Binder and the wedding pack read it there. The cast's own edits moved to lib/cast/actions. The example wedding stores its cast in the new place. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
A new tool, off until added from the toolbox: who walks down the aisle, in the order they walk, one at a time or in pairs or threes, which side they go to, and what they walk to and when the music changes. Its people are the same cast Group shots uses, picked with the same picker, resolved by the same code; so a mother named once walks and is photographed. "Suggest an order" starts from who is who: the officiant in place, the grandparents, the parents, the wedding parties, then the couple together. A role nobody is cast in is left out, the couple never are, and nothing in it assumes who walks with whom. What is left says when the processional names someone who is not set or no longer exists, as it does for group shots, and only while Ceremony is one of the wedding's tools; the front page has a Ceremony area. The example wedding has a processional and shows the tool. On the way: the member resolver moved to lib/cast as resolveMembers, taking any group with a label and members, and "Who's in it" became one MemberPicker both tools use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
The processional prints as one page for the officiant and whoever runs the day — who walks, in order, how, and the music and its cue — and copies as plain text to paste into an email to the wedding party. Both are made from one list of rows, so they agree. The page joins the wedding pack after the running order, once there is a processional. Planners keep a processional in the library: its order, who walks by what they are to the couple, how, and the music. Guests, families and the wedding's own roles are left behind, since none exist in another wedding; putting it into one replaces that wedding's processional, with fresh ids, as one undoable step. The library's kinds are also fixed in the database, so a migration, 20260929000004_library_processional, widens them; its test keeps a processional and still refuses an unknown kind. Apply it before deploying. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
A new tool, off until added from the toolbox. Each box has a number for
its label, a name, what is in it (how many, packed or not), who takes it
from the crew, and the part of the day it is needed for. Where and when
are that block's — its location and its resolved start — read from the
Timeline, never typed onto the box: "The suite, by 08:00".
One search over every box finds a thing ("shoes" → box 2); a thing moves
to another box from a menu on its row; "Add the usual boxes" starts from
four, UK first — the rings and the paperwork, getting ready, the day's
odds and ends, overnight — matched by name so it never doubles up.
What is left says when a box is needed for a part of the day the Timeline
no longer has, and, in the last week, what is still to pack. A box with
somewhere to be and nobody taking it is marked on the page. The front
page has a Boxes area. The slice merges box by box, so two people packing
at once both keep what they ticked. The example wedding packs for its day.
On the way: a crew member's name — the guest list's, for someone who is a
guest — is one personName, which Delegation now uses too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
A label for each box, four to an A4 sheet with dashed lines to cut along: the number large enough to read across a room, the name, where it has to be and by when, who is taking it, and as much of what is in it as fits, then "and 5 more". The packing list is every box and every thing, with a box to tick and the packed ones ticked; it joins the wedding pack after the jobs. The CSV is one thing to a row. All three are made from one list of rows, and say "where, by when" in the words the page uses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
A planner keeps a set of boxes: each box's number, name and what goes in it, with how many — not who takes it, which part of the day it is for, what is packed or its notes. Putting it into a wedding adds the boxes the wedding has none of by name, numbered on from its highest, nothing yet packed; like the checklist, it adds rather than replaces, so it asks nothing first. Which kinds add is one typed list, so a kind that replaces cannot be added without saying what it replaces. The database's kinds widen again: 20260929000005_library_boxes, proved against PGlite. Apply it before deploying. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
A tool off until added. The `bar` slice keeps only what the couple chose — the kind of bar, the crowd, a typed head count, and each figure changed from its default — and the amounts are worked out from the guest list on every render, so a guest saying no changes the wine. - Four parts of the day (reception, toast, meal, evening), each drinks per head of those drinking; a share not drinking has soft drinks instead; evening-only guests drink in the evening. - Every default in one table, as agreed with the maintainer: for 100 coming, 42 bottles of fizz, 36 of white and 36 of red, 9 cases of beer, 3 bottles of spirits, 10 litres of mixers, 50 of soft drinks, 100kg of ice — pinned in a test. - Every figure editable and put back in one click; less what they already have; rounded up to whole cases for sale or return; priced lines give an estimate. - The shopping list, grouped by where each thing is bought, as a PDF and as CSV. It joins the wedding pack while the wedding shows the Bar. - The whole-number field becomes one NumberInput with a step, for hours and prices. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
A planner keeps a bar as its kind, figures, mix, prices and shops — not how many are coming, the evening guests or what a couple already has — read through the Bar's own reader so only what it knows is kept. Using it replaces a wedding's settings and keeps its head count and what it has. One migration, 20260929000006_library_bar, widens the library's kinds, proved against PGlite. The plan, the spec and the roadmap record Phase 4 as built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
GitHub's agentic code-scanning job ("Code scanning AI findings", run 36626213114) stops before it analyses anything. Opening its session, GitHub's Copilot API returns Every run of this workflow has failed the same way, with the same stack. That includes all three runs on #19, for example 36533863701. So it's GitHub's configuration of the scanner, not anything in the repository, and there's no fix to make here. A re-run was refused: Generated by Claude Code |
Implements the toolbox spec: a way to add and remove tools, plus the four additions from the "Modular Workspace" PRD. Each phase has its own dated plan under
docs/superpowers/plans/.Three new migrations, applied in filename order before the code is deployed:
supabase/migrations/20260929000004_library_processional.sqlsupabase/migrations/20260929000005_library_boxes.sqlsupabase/migrations/20260929000006_library_bar.sqlEach one only widens the check on which kinds the library accepts. They can be run twice safely and need
20260929000001_library.sqlto be applied already.lib/library/migrations.test.tsruns them against PGlite.What changes
Phase 0: the toolbox
toolsslice, so the couple and their planner see the same set.Fontkit off every page
DEFAULT_FIT, pulled the font engine into every page. Moving it cuts the JavaScript every page loads from 522 KB to 393 KB gzipped.apps/fontEngine.test.tswalks both layouts' imports and names the chain if the engine comes back.Phase 1: Timeline travel and calendars
.icscalendar, either whole or just one supplier's part.Phase 2: one cast, and Ceremony
shotsinto its owncastslice, when a wedding is loaded, silently. It's read from either place until then, because the server reads stored documents too.Phase 3: Boxes
Phase 4: the Bar
lib/bar/sum.test.ts.Planners' library
Contract
SLICE_NAMES:tools,cast,ceremony,boxes,bar.day.utcOffsetMinis now nullable.Testing
No new dependencies.
🤖 Generated with Claude Code
https://claude.ai/code/session_01HozwaQN87Fzg985EBm6MY1
Generated by Claude Code