Seven nights from tonight
Plan is the week ahead, where home shows tonight — planning ahead is a different sitting from cooking tonight.
From SCREENS.md, Plan
Today is the leftmost day and the six after it are what you plan toward, with the sevens either side a step away. Owner’s ruling, 27 September 2026: "plan screen leftmost date = today, and plan toward the next 6 days".
From SCREENS.md, Plan
The strip is the whole week in one glance: seven days in a row, each its weekday and its number with a pip under it that fills when the night is planned
From SCREENS.md, Plan
Plan
SCREENS.md, the whole section
- Plan is the week ahead, where home shows tonight — planning ahead is a different sitting
from cooking tonight. Today is the leftmost day and the six after it are what you plan
toward, with the sevens either side a step away. Owner's ruling, 27 September 2026: "plan
screen leftmost date = today, and plan toward the next 6 days".
- A week is the seven days from today, not Monday to Sunday (owner, 27 September 2026, above). A calendar week left the part already gone on screen and planning only goes forward; a night behind you is one step back (13 September 2026: "Why doesn't the plan screen allow me to select different weeks or move anything or plan anything?"). Every seven holds tonight and six nights after it, so no Sunday with nothing left to plan exists: no empty region under the card, no "Plan next week ›", and the mover's first row is always seven nights. The strip shows one mark at a time, today outlined; a past day is marked only on a seven stepped back to.
- The way between the sevens is a row over the strip (
week-nav.tsx): a step either way in the accent, and between them what these seven days are called — The week ahead for the one starting today, and the dates it covers for every other, since a seven anchored to nothing has no name a cook counts from (date-words.ts). Only while you are away, Today as a grey word-button (.word--back) beside it, the way back. Real buttons rather than a swipe, which is invisible, unreachable by keyboard and undiscoverable. Which seven you are looking at is where your thumb is, not a fact about your plan: every mount opens on today. - Another seven opens on its first day. Tonight is only on the one starting today, so
stepping selects that seven's first day and the card is that night's — headed by its date,
with one yellow to plan it by name or the way to its recipe, exactly as any other day of the
strip selects (below). All seven of its nights are rows, the card's among them. A night
behind you is drawn as it was and offers nothing: no plus, no pencil — but for one
dish nobody cooked, below — and a seven
that has entirely gone heads its rows by the dates it covers rather than What's coming —
nothing on it is coming (
weekPick'sgone). Every seven behind you is entirely gone now, since one ends yesterday.
- The pick is a strip and a list, with a card for a day you tap — lane B of the board, "the
week as a strip", less the two sentences it had under the list (below);
design/week.mjsis its deck andviews/week-pick.tsthe fold every part reads. Tonight is a row of the list and never the card.- The strip is the whole week in one glance: seven days in a row, each its weekday and its number with a pip under it that fills when the night is planned — a note as much as a dish — today outlined where it falls. It answers the shape of the week — how much of it is spoken for.
- And every day of it selects the card, today excepted. Owner, 18 September 2026: "on
the calendar, selecting a specific date should set the main card to that date, and even past
days of the week should be selectable and viewable." Each day is a button (
aria-pressed, one at a time; today alsoaria-current="date"), and the pressed one wears the readings' own mark for the open one — a bar under it in the deeper yellow, its name in the brown — beside today's outline, so a Wednesday looking at Monday shows both marks and greyscale tells them apart. Today is pressed on every mount, and pressing it takes any card away; a step to another week presses its first day. Which day is pressed is where your thumb is, not a fact about your plan. - Today is a row, never a card. Owner, 2 October 2026: "Today's cook is too big on the
plan screen, just leave it as a normal row. The home card is already huge." Home carries
tonight at size (§1), so the plan drew it twice and pushed the week down. Tonight is the same
row as every other night, in the same order, with what a row has: its date in a column, the
workstreams, the dish and its facts and, at the end, one pencil — or, with nothing on, its word and
a plus (below). What marks it is
Today where the weekday would be, in the accent
(
planWords.week.todayShort, "auj." in French because the column has no room for a long word), said to a reader as "Wednesday, Tonight" witharia-current="date"as the strip's today wears. Its row leads to the brief, which is where Start cooking went, so what the card lost is its loudness and nothing it did: there is no yellow on the plan at rest. - The card is a tapped day's, home's bones: the date in the accent — "Thursday 10 ·
Tomorrow", any other day its weekday and number alone (
plan-words.ts) — the dish's name large, its time under it, and the one yellow on the screen: Open the recipe on a night with a dish, or Plan Thursday when there is nothing on, which opens the picker (below). Under the yellow three plain words, Move, Clear and Add a recipe; never a second dressed thing. Add a recipe is the card's too because the night's own Add stands in a list a few rows high under the card, below the fold of a short phone — it was there and the picker opened under it, where nobody could see it — and the card is where a thumb already is. Its acts write the night it shows and no other.- A day that holds several things, or only a note, is a different card
(
WeekCard.kind). A yellow cannot say which of two dishes it opens, so the card does not choose: its date, then each thing on the day as a line — a dish its name and its time, leading to its recipe, a note in its own words — and plain words under them: Add a recipe always, and Change and Clear where the day holds only that one note, which can be changed or cleared like a planned recipe (they write the note, in the card's own field). No yellow, and no Move; with several things, Move and Clear are each row's own below it, behind its pencil. The card for one dish is still the dish named large. - A past night is viewable, not editable. Its card is what it held — the dish in the receding ink the rows give a gone night, or "Nothing was on." — with no yellow, no Move and no Clear: moving or planning a night that has gone would rewrite history, and the yellow marks live work, never history (DESIGN). The way to its recipe is a plain word, Open the recipe, since the rows already offer that of a gone night.
- Selecting a day moves the card and nothing else. The nights are the same seven, whichever day is pressed — the list is the region a thumb scrolls, and a list that reshuffled under every tap on the strip would be the seven stepper rows back by another road. So the selected night may appear twice, on the card and in its row; the row is where it was and the card is where you asked.
- A day that holds several things, or only a note, is a different card
(
- What's coming is every night of the seven in calendar order, planned or not (the owner, 7
October 2026: Monday the 30th listed after the 1st to the 4th of the next month "should be
before"; the planned-first order it replaces broke the calendar across a month). No night
before today is listed, however many went by uncooked (below). A planned night is its date
in a column (the number large in the serif, in lining figures so a column of dates and the
strip's seven read even, the weekday under it), the dish's workstreams as a glyph, the name, and
its time under it — "57 min", or "20 min · My time" where this kitchen has saved evenings
on the dish, the shelf row's own facts off the same fold (
shelfRowFacts), each fact after the first leading with its own dot, so a line that has to break breaks before one and never ends on it — then one pencil at the row's end, behind which are Move, Clear and Add (below). No scale on the week (owner, 22 October 2026, on the difficulty slider: "the difficulty looks terrible", "Build G"): the workstreams' glyph at the row's start is its only sign of how hard. Owner, 6 October 2026: "For the sublabels on plan, just show hands on time and difficulty rating, not total time and number of things to buy." Amended the same day (the quote is on the shelf row, above), so the first fact is the time and not the work: this kitchen's own where it has saved any (useMyTimes, which the screen reads), saying "My time", else the recipe's own, the figure the brief prints. Never hands-on time, never what there is to buy, never "on the list". A dish whose graph has not been read says no word, and one whose recipe commits no time, and has none saved, says no line under the name: the row says less rather than a figure nobody stated. An empty night is its date, the word, and a plus that opens the picker. These rows are the one region of the screen that travels. - No night before today is listed, and no row says Not cooked. Owner, 6 October 2026:
"Previous dates dont matter, you can go back with the top date nav, but should never show by
default. Also why is one of them showing a not cooked label? Don't show that." A night that
went by uncooked is home's question, asked once under tonight's card (§1); the seven that
start today reach back no further than today, and the fold (
weekPick) draws nothing it was not given a day for. Going back keeps working: a seven stepped to with the way between weeks draws its nights as they were, headed by the dates they cover, and a dish nobody cooked on one of them keeps its pencil, with Move and Clear (NightDish.notCooked, read from the plan and the cook log every render, never stored), with no word to say why. The other nights of that seven are history with nothing to press, and a night a week old is plain history whatever it held.design/week.mjsdraws it and the drive walks it. - A night is one block of rows, each ending in one pencil. Owner, 4 October 2026
(
night-rows.tsx,night-entry.tsx), amended 6 October. Its date is said once, on the first row, and every thing it holds is a row of its own with the date's column left blank — a dish its workstreams, name and facts, a note its own words in the sans and the full ink, where an empty night's word is in the receding one — in the order they were planned, ruled once, after the last. Every row ends in the same pencil, and Move, Clear and Add (a note's Change, Clear and Add) are behind it; there is no row of its own that adds another, and no Add on a row at rest. "The add row appears only under the night you tapped, never under every planned night, so the week stays one screen" — the 4 October ruling — and 6 October's "Just say add": the word is Add, which is all the button says, and its name for a reader says the night ("Add a recipe on Friday"), since a word that is only a verb cannot say which night it adds to. An empty night keeps its plus, which was never the row that adds another; Add is not drawn while the shopping choice is open or on a night that has gone. Add opens the picker in place under the entry whose drop-down it is in, and brings that night's date to the top of the nights so the field is in view. With a card above the nights, a picker opened for the card's own night opens in the card: the nights are a few rows high under a card, and a picker there is a field nobody can see. A panel opened under a night's row takes the room the card had (the card is not drawn while it is open), for the same reason; the pencil's small row alone is no panel, and the card stays. A note counts as the night planned: its pip is filled, it sorts with the planned nights, and it carries no workstreams, no facts and no ring — nothing to buy, nobody to cook it. The cost of the acts is one small row on one entry, a thumb high, however many nights are planned. - No row is selected, and the pencil drops one small row. Owner, 6 October 2026: "There
should be no selection of the row anymore. Selecting the row is difficult because you click
on the recipe name, and that links to the recipe, which we need to keep." No night is chosen
by a tap and no button lies over a row: the name and its facts are the link to the recipe, and
the rest of a row answers nothing. The way to Add, and to Move and Clear, is the pencil:
the grocery list's own mark (
Icon edit, the one.list__markwears), a--tapbox at the row's end in the quiet ink (--on-surface-variant), named "Edit" and the dish or the note's words (planWords.row.edit, "Modifier"), witharia-expandedandaria-controlsnaming what it drops (night-edit.tsx).- It drops one small row directly under the name, its words starting where the name's
letters do: Move, Clear and Add for a dish, Change, Move, Clear and Add for a note (whose
small row starts where its words do, since it has no workstreams before them), then an up and a
down arrow on a night of two or more (below), side by side, as the
app's own word-buttons (
.word, DESIGN: Inter 600, mixed case, no underline, a--taphigh) — Move, Change, Clear and Add all in the gold (owner, 13 October 2026: "all three words gold") — and the row's rule under it, being the row's. Move, Change and Add open the mover, the note's field and the picker under it, with the small row staying open above them; a second tap of the same word goes back to the small row, and a second tap of the pencil, or Escape (which returns the thumb to the pencil), shuts everything. One is open at a time across the whole screen: opening another pencil, or the strip's day, shuts the last. A dish nobody cooked on a night that has gone keeps its pencil with Move and Clear and no Add. - A dish's Clear asks first, on a night still ahead (owner, 8 October 2026: "Yes, confirm
before clearing";
clear-night-ask.tsx). The small row is replaced by home's own row (ConfirmAsk, the row: the act in the same word, Keep it, no question), the pencil staying lit; the dish comes off the night only on the act, and Keep it, Escape or the pencil leaves the night as it was. The card over the nights (§1b above) asks the same way in place of its acts. A note and a dish on a night that has gone are let go in one tap: nothing is planned behind the one, and the other is history (§1, "the dinner nobody cooked"). - While it is open the pencil sits in a soft round of the container tone, in the primary ink, so the row that owns the small row is the one lit.
- It stands where the plus of an empty night stands, and the deck measures that. Owner,
6 October 2026: the pencils must be inline with the plus icons below them. Both are a
--tapbox flush with the row's end — the same width, the same right edge — and the icon's centre is on the plus's centre:controlClaimsindesign/week.mjsreads the middle of each mark in the page, at 390 and at 360, in both palettes, and holds them within a pixel. The pencil's box reaches into the row's own padding so a one-line dish is a tap tall and no taller, and the second thing on a night, which has no padding above it, starts at its top edge; no row at rest is ever three taps tall. The row's columns are a grid (wnext--entry): the date, the workstreams, the name, and the pencil's column. - The cost is nothing at rest and one word's height open, where the stack it replaces
cost two or three taps on a row. Which entry is open is where a thumb is and so is never
stored; the nights still bring the open row, and what it opens, into view if it would be
below the fold (
useRowInView), and a write still brings the night just written to into view (useNightToTop).
- It drops one small row directly under the name, its words starting where the name's
letters do: Move, Clear and Add for a dish, Change, Move, Clear and Add for a note (whose
small row starts where its words do, since it has no workstreams before them), then an up and a
down arrow on a night of two or more (below), side by side, as the
app's own word-buttons (
- What you just planned stays in view. Planning an empty night moves it up among the planned
ones, above where the nights were scrolled to, and the cook was left looking at nights with
nothing on them. The nights bring the night just written to into view again whenever a write
moves it out (
useNightToTop'slanded), and leave it where it is when it is already in view. - A planned dish can be moved, and a move never loses a decision. Owner's ruling, the
same day. Move opens the mover under the row (
night-mover.tsx), in place like the picker: the nights still ahead of the seven you are on and the whole of the seven after — and, on a seven you stepped to, all of today's own first, so a dinner pushed a week on can come back to tonight — as rows of the strip's own cells, each under the strip's own day so a row that starts part-way through still lines up (views/move-nights.ts). One tap on a night is the move. A night that already holds something is marked — the cell wears the strip's mark and its name says what it already holds — and the dish joins it: a night holds several things, so nothing is swapped out, and a move that deletes or relocates something the cook did not touch is not a move (movedinviews/plan-night.ts). The dish is written fresh, so nothing about the night it left follows it. A note moves the same way (owner, 20 October 2026: "A note alone on its night could still be moved to another night"): its pencil has the same Move beside Change, the note joins the night it lands on last, and the same words already there make it one note. Which row's mover is up is where your thumb is, like the picker, and one is open at a time. - An entry, a dish or a note, can also be carried by its grip, and Move stays as the tap
path (sq-m5at, sq-v5pt.238;
plan-drag.tsx,night-li.tsx; picked as drawing A, 20 October 2026). Every dish and every note on a night still ahead wears the app's own grip, two hairlines in a 20px rail left of the pencil, a note alone on its night too; an empty night and a night that has gone wear none. Only the grip lifts anything, and only after the app's one hold (lib/drag-hold.ts: 350 ms, ten pixels of slop), so a scroll that starts on any part of a row is the page's and lifts nothing; the name stays a link. The entry rises as raised paper with the night's date left in its slot, and the night under the finger lights as one block in the strip's chosen pair. The strip's days are targets too (a night that has gone is not), and so are the week's two arrows: held over one for 600 ms the week steps and steps again every 600 ms, the entry staying in the hand. Letting go over another night ismoveOn, the pencil's Move write, so the entry joins that night last and nothing is swapped. Held over a row of its own night, the rows part where it will land and the old place closes (drawing A, "a gap opens"; the aisle order's own sortable list, so the night keeps its height and the date goes with the first row drawn); letting go there isplaceOn(placedinviews/plan-night.ts: the entry at that row's place, every other night untouched). Over its own place or over nothing it settles back and writes nothing. The pencil's menu gains an up and a down arrow on a night of two or more (the first entry down only, the last up only), on the menu's one row with its words (owner, 20 October 2026: the words wrapped it to two), each named Move up or Move down and the entry for a reader, written through the sameplaced, so a tap and a drag cannot put an entry in different places. The edge scrolls the nights at most 300px a second. The grip is for a thumb and a mouse: it is hidden from a reader and takes no focus, and a reader or a keyboard moves an entry by the pencil's Move, Move up and Move down. - A note is written from the picker, changed in place and cleared in one tap. The picker's
field takes a note as well as a recipe, and says so ("Search or write a note"):
there is no mode to switch, a line that is a recipe's name finds the recipe, and any line
typed is also offered first as a note, in the sans and said as the act it is ("Add “Dinner
at Mum’s” as a note"). Over the field stand three one-tap notes on one row — Eating
out, Frozen, Instant — as pills that are never yellow or pressed, since a tap writes.
A pill is shorter than the line it writes: Frozen puts Something frozen on the night
and Instant Something instant, so home's card and every other place a night is read keep
the whole line, and a reader of the screen hears the whole line as the pill's name (French:
Dehors, Surgelé, Rapide). Owner, 13 October 2026: "The eating out, something frozen,
and something instant all need to fit on a single row somehow, and the search needs to be
right next to the results so its more clear where youre actually searching." So the notes
are the top of the picker, the field sits directly over the recipes it searches, and the
short words are what let three pills share one row at 360 (measured, in both languages; the
deck holds it at both widths). Change opens the note's words in a field under its row
with Save beside them and the same three pills under that (
note-changer.tsx): a note is changed, not searched for, so it carries no recipe list. A blank line is no note, and the same words twice on one night are one. Clear takes it off in one tap and asks nothing, unlike a dish: nothing is behind it. - There is no shopping section. Owner, 21 September 2026: "Remove the shopping section on
the plan screen." A dish reaches a list from its own brief — the ingredients reading's
Add to list (§2), which the brief's basket writes as
lib/dish-lines.tslines, each saying which dish it is for — and home's SHOPPING tile (§1) is the way to the list itself. This screen says nothing of what there is to buy: the row's second fact was once "9 things to buy" or "on the list", and the owner's 6 October ruling (above) took it off the rows in favour of the dish's time and how hard it reads. The deck and the drive assert the section's absence, and the absence of both facts, so nothing grows them back with every other check green. - But some of the week does reach the list from here, and a tick says which of it. Owner,
27 September 2026: "Add to list offers a checkbox per day across those six rather than taking
all of them." The act is one word-button (
.word) at the end of the row headed What's coming, which is the shared section label (.label, brown) — Add to list, naming the list only where it is not the Grocery list every kitchen has — and tapping it turns every planned dish, tonight's among them, into a tick box, all of them ticked: a cook who opened this is shopping for the week, and what they came to say is which of it they already have in. The yellow that replaces the act says how many dinners it will copy ("Add 4 dinners") and the way out is the plain word beside it, in the act's own spot, so nothing on the row moves: the row is as tall as its label, each act reaching out of it for its thumb-high tap, so planning the first dinner and opening the choice move the nights by a pixel or two. A dinner is a night: a main and a side on one night are one dinner, and the count says "Add 1 dinner" for them both ticked as it does for the main alone. A tick box is a dish's, not a night's: a night with a main and a side has a tick for each, and the main can be left out with its side kept (use-week-basket.tskeys each byplannedMealKey). An empty night grows no tick box — there is nothing to put on a list — nor does a note, which has nothing to buy, and a night that has gone is not offered either. The pencil stands aside while the tick boxes are open, with the Move, Clear, Change and Add behind it. - While that choice is open the card stands down. One yellow on a screen, and it is the act still to finish: the card keeps its words with the plain one a gone night gives its recipe, and Move and Clear stand aside with it, so the only question being asked is the one the cook opened. The same ruling the brief follows when its own Add to list takes Start cooking's seat (§2).
- The write is
lib/dish-lines.tsand nothing else, the one path onto a list —hooks/ use-week-basket.tsputs every chosen dish through it in a single store turn, so seven separate writes cannot read the plan back and let the last one win. A dinner planned twice in a week shops once: the lines carry the recipe's own ids, so the second copy would land on top of the first. Adding is a decision about shopping and never about the calendar; it puts no dinner on a night. - And no sentence about the nights behind you. Owner, 13 September 2026: "the behind you section is too long and useless." Nothing a cook planning a week acts on was in it; the evenings themselves are the recap's and the thread's (§4, §2).
- The picker is a search over your own recipes, in place — under a tapped day's card or
under the night's row, never a sheet — and it is a filter, not a ranking: the finder's question is
what's for dinner, this screen's is what goes on Thursday. Planning a night adds to
whatever was there and replaces nothing (
views/plan-night.ts): a dish the night already holds is not offered, since a tap on it shut the picker and did nothing, with no word to say why (asking for one anyway is still a no-op underneath, not a second copy). The field has no magnifier — a card at 360 has the width for the whole hint, "Search or write a note" (Chercher ou écrire une note), or for the mark, and the hint is what says it takes a note. It prints no count: the shelf's "Search 8 recipes" fits, but the same words with a note ran past the field at 360 (the empty field holds back room for the clear mark) and a bigger library's number only lengthens them, so the hint is the shelf's verb and the note, whole at any size of library (the deck measures both languages in the field itself).- Under a card, the recipes are what scroll, and they keep their room. Owner: "if I
click a future day on plan like Wednesday, and click plan a meal, the recipe list doesnt
scroll." The card is furniture, and a picker that opened in it grew it past the nav on a
short phone with nothing able to reach the last recipes. Open, the card gives instead — and
what it gives up is everything above the picker: its eyebrow with Cancel at the end of the
line, what the day holds as one line of names (two lines at most), and the picker, with no
yellow, Move or Clear. The yellow opened the picker and has nothing left to say; the lines a
busy day holds would otherwise have taken the recipes' room, and on a day of a note and two
dishes they left the list 13px tall at 360x640 and 37px at 390x664, a scroller that scrolled
and showed nothing. The list shows at least
LEAST_SHOWN(120px): two rows and part of a third (tools/lib/picker-scroll.mjs, which the deck, the drive andpnpm enginesall judge), and the nights below stand aside until it is shut. The same holds for the mover opened on a card, which keeps its yellow since it is the dish's. Under a night's row nothing changes — the picker is in the nights, and those already scroll. The deck holds it at both widths, at the height a phone has with Safari's bars showing, the drive scrolls it in Chromium, andpnpm enginesin WebKit.
- Under a card, the recipes are what scroll, and they keep their room. Owner: "if I
click a future day on plan like Wednesday, and click plan a meal, the recipe list doesnt
scroll." The card is furniture, and a picker that opened in it grew it past the nav on a
short phone with nothing able to reach the last recipes. Open, the card gives instead — and
what it gives up is everything above the picker: its eyebrow with Cancel at the end of the
line, what the day holds as one line of names (two lines at most), and the picker, with no
yellow, Move or Clear. The yellow opened the picker and has nothing left to say; the lines a
busy day holds would otherwise have taken the recipes' room, and on a day of a note and two
dishes they left the list 13px tall at 360x640 and 37px at 390x664, a scroller that scrolled
and showed nothing. The list shows at least
- Which night's picker or mover is up is not stored, and nor is which day the card shows or which night was tapped. All are where your thumb is, not a fact about your plan, so they are component state: every night is shut, today is pressed and no night is tapped on every mount; a step to another week shuts them again and presses that week's first day, and a tap on the strip shuts them and presses the day tapped.
- How many each night is for is the brief's number, and only the brief sets it (owner, 25
August 2026, restated by the pick). How much is made is
Recipe.scale(AMOUNTS), a multiplier and not a headcount, §2's own field and §2's ownScaleStepper; the week reads it when it builds the shop, so a scaled plan produces a correctly scaled shop with no arithmetic by the cook, and there is no second number. A scale is decided about a dish, and the same dish on two nights is one scale.
What a night holds
A night holds any number of things, and a thing is a dish or a note.
From SCREENS.md, What a night holds, and the dinner nobody cooked
Owner, 4 October 2026: "when you’ve planned one recipe for a day, you should get a new add recipe row for that same day if you need to plan multiple"
From SCREENS.md, What a night holds, and the dinner nobody cooked
A note is the cook’s own words and nothing else — out, something frozen, something instant, or anything typed. It counts as the night planned, and it carries no shopping and no cook
From SCREENS.md, What a night holds, and the dinner nobody cooked
What a night holds, and the dinner nobody cooked
SCREENS.md, the whole section
- The plan is the one thing not folded from a graph. "I'm cooking this on Thursday" is a
decision; it lives in
MealPlanbehind the third store port, with the ticked grocery lines. - A night holds any number of things, and a thing is a dish or a note. Owner, 4 October 2026:
"when you've planned one recipe for a day, you should get a new add recipe row for that same day
if you need to plan multiple" and "a way to put a note instead of a scheduled recipe if im
planning to be out or have something frozen or instant." A main and a side share a night, and
nothing planned on it replaces anything else. An entry is its night and its dish, or its night and
its words (
plannedMealKey,meal-plan.model.ts), so the same dish twice on one night is one entry and two phones that each add a different one both keep theirs: the merge is a union per entry (applyPlanDelta), and retyping a note reads as one taken off and one put on. A note is the cook's own words and nothing else — out, something frozen, something instant, or anything typed. It counts as the night planned, and it carries no shopping and no cook: no recipe, so nothing reaches the list, nothing is ranked against it, and no question follows it when the night goes by.views/plan-night.tsis the one home for how a night is written, which every screen below uses (§1b, §2, home's line about a dinner nobody cooked). - A dinner you planned and nobody cooked is asked about on home, for six nights. Owner,
4 October 2026: "if a recipe is planned on a day but we don't see them cook it, can we prompt to
reschedule it". A plan is pinned to a date, so an uncooked one used to leave the screen at
midnight in silence, and carrying it forward would put a dinner on a calendar nobody agreed to.
So the dish stays where it was planned and home offers the two things a cook can do with it:
move it to another night, or let it go, one tap each. The plan itself does not list it
(6 October, below).
- Cooked is read, never stored (
uncookedNights,libs/core). A dish planned on a night that has gone is uncooked when the cook log holds no session of that recipe started on that night, by the device's clock — the clock the plan's dates are already in. Started, and not finished: an evening that reached the stove was not missed. That night, and not a later one: cooking the dish on Thursday does not make Tuesday's plan true, and Clear is one tap away. Nothing is written — no flag on the plan, no event — so a move or a Clear changes the answer by changing the plan, and there is nothing to forget to unset. The two screens ask one hook (useUncookedNights), which reads the log only when a night in the window holds a dish. - Six nights, and then not again. A night is asked about from the midnight that makes it a night gone until it is a week old, and then nothing says a word: the plan shows it as history and home never names it.
- A note is never asked about, and a night that held two dishes asks about each. The question is about a dish; a night spent out or on something frozen went by as it was meant to, and answering one dish touches nothing else the night held.
- On home it is one quiet line under tonight's card (§1), and Move there names the night it lands on — the first with nothing planned, which is tonight unless tonight is taken, a note taking a night as much as a dish — so it opens nothing and takes one tap. On the plan it is no row and no word (§1b, 6 October 2026); a seven stepped back to keeps Move and Clear on the dish.
- Quiet, and never the loud thing. The one yellow action belongs to cooking or planning tonight. Clear does not ask: it lets go of a night that has already passed.
- One fact, in the owner's short declaratives. Not cooked, and no reason, no schedule, and no claim about whether the shopping was done: an unticked list is not evidence nobody shopped.
- Cooked is read, never stored (
The dinner nobody cooked
A dinner you planned and nobody cooked is asked about on home, for six nights.
From SCREENS.md, What a night holds, and the dinner nobody cooked
So the dish stays where it was planned and home offers the two things a cook can do with it: move it to another night, or let it go, one tap each.
From SCREENS.md, What a night holds, and the dinner nobody cooked
Not cooked, and no reason, no schedule, and no claim about whether the shopping was done: an unticked list is not evidence nobody shopped.
From SCREENS.md, What a night holds, and the dinner nobody cooked
Two phones, one plan
two people in a house shop from one list, and if she adds milk and he cannot see it, the feature has failed exactly the household it exists for.
From KITCHENS.md, The plan, the list and the hob
The plan stays one document: two people rarely edit the same night, a calendar is read whole and is small, and a clobbered dinner is visible and re-typed in seconds where a clobbered tick is silent.
From KITCHENS.md, The plan, the list and the hob
The plan is one document (every other family merges by id), so two phones in one kitchen once took turns erasing each other: a night planned at home pushed the whole cached copy over the ticks made at the shop, and the shop's next push put its copy back.
From ARCHITECTURE.md, A push carries what changed since the plan it took
And what actually stops either being clobbered is a merge, not the rows: a device pushes what it changed since the plan it last took, and the kitchen folds that in by night, by aisle, by list and by line — what a side changed is its answer, everything else the other's
From KITCHENS.md, The plan, the list and the hob
The plan, the list and the hob
KITCHENS.md, the whole section
The plan and the shopping list belong to the kitchen, and this is the case that is broken today rather than merely unmodelled: two people in a house shop from one list, and if she adds milk and he cannot see it, the feature has failed exactly the household it exists for.
Which forces one thing that was already queued and now stops being optional: a grocery list is
rows, not part of the plan document. One document per tenant with two shoppers in it means one of
them ticks an item in an aisle and the other's write erases it, and a lost tick costs a second bottle
of milk — the failure a shopping list exists to prevent. The plan stays one document: two people
rarely edit the same night, a calendar is read whole and is small, and a clobbered dinner is visible
and re-typed in seconds where a clobbered tick is silent. And what actually stops either being
clobbered is a merge, not the rows: a device pushes what it changed since the plan it last took,
and the kitchen folds that in by night, by aisle, by list and by line — what a side changed is its
answer, everything else the other's (ARCHITECTURE, "A push carries what changed since the plan it
took").
aisles stays on the plan and becomes the kitchen's, which is a small gift — it is knowledge about
milk rather than about Tuesday's milk, so a correction one member makes is one the other never has
to make.
The hob belongs to the kitchen. Kitchen is the tenant row itself — kitchenSchema in
libs/model, carrying its id, its name, when it was made and what it can cook on. It became that
from a bare burner-and-oven count in libs/core, which is what the count was always waiting to be:
you join a kitchen and it says what it has, so several people cooking in one place agree
about the burners they are sharing. Two people who share a kitchen only to share recipes will
sometimes be standing at different hobs, and then the count is wrong for one of them. That is
tolerable, and worth saying why rather than leaving as a hole: kitchenLoad only ever reports
overflow — it never refuses a step and never reschedules — so a wrong count is a slightly wrong
warning, never a wrong dinner. A per-cook override is additive if it bites.
A push carries what changed since the plan it took
ARCHITECTURE.md, the whole section
The plan is one document (every other family merges by id), so two phones in one kitchen once took turns
erasing each other: a night planned at home pushed the whole cached copy over the ticks made at the shop,
and the shop's next push put its copy back. So a push carries only what this phone changed: each write
to the plan is noted as what it changed from the plan the cache held (diffPlan), an operation of its
own (below). The server lays each over what the kitchen holds by applyPlanDelta
(merge-plan.ts states the one rule and what an absence
counts as), which only ever carries the keys that moved, under the kitchen's advisory lock, read and
write on one connection, so two pushes fold in turn rather than over each other. A first plan made
before a phone ever synced folds into the household's rather than over it. A tap on the phone goes the
same way into IndexedDB (PlanStore.apply). The journal still keeps planBase, the plan as the phone
last took it (advanced only to a pulled plan the cache applied), for the kitchen's list order and for a
journal with no operations to send.
The delta is keyed by what the merge already keys
(plan-delta.model.ts): nights by date and dish,
learned aisles by food, kitchen aisles by id, each as set and unset; lists by id, each with only the
lines that moved, a line as the item or its tombstone, and its name only where this phone made or
renamed the list, so a tick from a phone holding the old name never undoes another phone's rename.
Every store's apply and put write only the rows that differ. On six lists of 30 lines, one tick's
push went from 31,366 bytes (plan plus planBase) to 249 (the change is 167 of them, its operation's id and wrapper the rest), and the
IndexedDB write from seven rows to one. The pull is cut the same way:
cursors.plan is the newest list stamp the device has been answered, plan.lists carries only the
lists stamped after it, and planLists names every list the kitchen holds, in order, so the phone lays
the answer over what it holds (layPulledPlan); the plan's own row still comes whole. That tick's pull
went from 15,663 bytes to 2,634.
Protocol 6 changed the shape and closed no window. SYNC_PROTOCOL and PARTIAL_PLAN_PROTOCOL are 6;
OLDEST_SYNC_PROTOCOL did not move. A protocol-5 or -4 build still pushes its whole plan with
planBase, folded as the change between them (mergePlanInto is diffPlan then applyPlanDeltaInto,
so one rule serves both), and is still answered the whole plan without planLists; a push with no base
at all (a build older than the field) is applied whole. Neither is deduplicated: only a protocol-6
push carries operation ids. The push channel still tells the other phones the whole merged plan.