← All privacy impact assessments

PIA: Shopping and preparing a supermarket basket

Status: Assessed before implementation for a limited, invited group pilot, and reviewed for general release on 6 October 2026 (section 8). Revised again on 7 October 2026, before any of it was built, for shops that fill the member's Woolworths cart, a run status the whole group can see, de-identified prices observed in that cart, a structural meal-plan marker on a shopping item, an optional product-matching choice and an Arrange pickup task. All six are now built (7 October 2026) and this assessment has been read back against the code; where the code settled somewhere the design had not, the sentence was changed rather than the code. Nothing in them has been exercised on a phone. A run with the phone locked has been seen working on one iPhone. Opening the retailer's app at the cart has not been verified, and this assessment does not claim it. Revised again on 10 October 2026, before any of it is built, for the change that gives Shopping records of its own: two new tables hold a group's shopping lists and their items; everything already on a list moves into them once, in a single database change, and the rows it came from are frozen and then deleted; and a typed item is tidied by a quick judgment from TypeSafe, the same United States service the assistant's fast commands use, which decides whether an item is one the list already holds, whether a comma list is several items, and which aisle an item belongs in. That part of this assessment describes a design, not something working. Nothing in it exists yet, and sections 3 and 8 set five conditions — C1 to C5 — that the change has to meet for the statements here to stay true. Built on 12 October 2026, not yet released. Shopping's own items are implemented as phase 3 of the routines plan: the two tables, the one-way move of every existing item, the Shopping tool, the saved runs, the assistant's reads and writes, and the tidying of a typed item. What the building changed about this document is recorded under "What differed" in section 8, and the three narrowings are in section 4. Nothing here has been seen on a screen: the simulator pass was not run, by a decision recorded on 12 October 2026.

Notice written on 15 October 2026 (condition C5 met). The privacy policy of that date names a typed shopping item as something TypeSafe receives, in its section on artificial intelligence and in its what-changed list; the route's minimum notice version is that version; and the setting that admits the tidying is declared off in our infrastructure configuration rather than left unset, so switching it on is a deliberate, recorded act that reaches only members who have seen that notice. The J5 questions have still not met a screen.

Revised on 20 October 2026, before it is built, so that a shop somebody has left no longer blocks the group. Another adult in the group can clear a shop that has gone 30 minutes without a change while running or waiting, or 6 hours while ready. The change is in section 3, under "The group's view of a shop", and in sections 5 to 8.

Revised on 28 October 2026, before it is released, and accepted by the founder the same day, for the order in which models choose a product: TypeSafe's Jev first (on by default, used only at a probability of 0.9 or more by the founder's decisions of that evening, 0.95 or more since 31 October; for Basic and Standard products only since 29 October, after a second experiment), then Gemini 3.8 Flash with 3.7 Flash behind it, then Gemini 3.5 Flash-Lite, which no longer races Flash. The change is in section 3, under “Choosing a product”.

Also revised on 28 October 2026, before it is built, so that a shop adds each product to the cart as soon as it is chosen rather than after choosing them all, and a question can be answered while the shop runs. Nothing new is collected, sent or kept. The change is in section 3, under “Adding each product as it is chosen”.

Revised on 28 October 2026. "Download my data" now includes a member's Shopping lists and their items, for every group they belong to. The archive reads them through the member's own sign-in, the way it reads their tasks, so it holds the shopping records that member is permitted to read, which includes archived lists the app no longer shows; it adds nothing about other members beyond who created or ticked an item. Sealed words go out as stored, with the key that wraps them, and the archive's existing sentence about encrypted text now names shopping lists and items. It does not say we cannot read them: that sentence is true only of photographs.

Revised on 3 November 2026, before any Coles code is written. Status: Assessed before the code (draft, 2026-11-03); founder approval pending. Coles is added as a second supermarket, by live search on the member's phone and one link that adds the chosen products to the member's own Coles trolley. The change, its nineteen conditions (CL1 to CL19), its residuals and a note on the policy wording are in section 3, under “Coles”. This is the review section 9 asks for before another retailer is added; until it is approved the sentences below that put Coles outside this assessment still stand.

Revised on 7 November 2026, before it is built, so that a shop can take up to 30 minutes, by the founder's decision of 6 November 2026. If the phone ends background work on a shop that is still going, the shop pauses and continues only on the member's tap. Nothing new is collected, sent or kept. None of this has been seen on a phone.

Revised on 7 November 2026, with wording accepted by the founder that day, to name every product-page fact read when looking further and record the accepted residual for a name that is also a grocery word.

Written: 4 October 2026 · Last revised: 7 November 2026

Nothing here is legal advice. This is the app’s assessment of Shopping.

1. Purpose and scope

Shopping collects a group's meal ingredients, pantry replenishment and other shopping items in one tool, and lets an eligible member prepare a Woolworths basket on their phone. Shopping in person (added 6 October 2026) shows the same lists, and marks an item as being collected through a claim that already existed — the item's assignment, which the group could already see; it adds no data, flow or recipient. Until the change assessed on 10 October 2026 those lists are group tasks with their items filed underneath them, and the Tasks tab shows both; afterwards the items are Shopping's own records, the claim is a field on the item, and the Tasks tab keeps only the shop itself, linked to Shopping. The person reviews and places the order in Woolworths' own app. Coles (assessed in a 3 November 2026 amendment, section 3, not yet approved), unattended scheduled orders and purchases are outside the assessment above.

What the 7 October 2026 revision covers. Six changes to the same tool, all of them now built and none of which places an order:

Still outside this assessment: Coles, orders, checkout, payment, booking a pickup time, shops that run without a person starting them, and any screen that shows a member a price.

What the 10 October 2026 revision covers. Two changes to the same tool, neither of them built and neither of which places an order:

Still outside it, as before: Coles, orders, checkout, payment, and a price shown to a member.

2. Data involved

A group’s shopping notes (section 3, “Shopping notes”): free text, stored in shopping_notes, readable by the group’s adult members.

Shopping descriptions, checklist state, meal-plan links and assignments already belong to the group. Until the change assessed on 10 October 2026, Shopping reuses their existing encrypted task storage as a compatibility layer, presents typed shopping items, and moves ingredient checklists out of the Tasks view into Shopping; existing clients keep the same rows, so there is no second competing shopping list and no destructive conversion. That change ends the compatibility layer rather than adding a second list: the rows move once into Shopping's own tables, under the same group key and with the same identifiers, and the rows they came from are frozen rather than left as a second authority. Nothing is converted into a readable form on the way, and no version of the app can write to both shapes.

Product choices, fulfilment preferences, the product preference and run progress are private to the initiating member and phone. A retailer browser holds login cookies. The member enters credentials on the retailer’s own page. GroupApp collects, saves and fills none; legacy saved-copy removal and its limits are described below. A retained retailer session is a credential even when its password was not retained.

Purchases may reveal a child's needs, dietary restrictions or health information. Shopping does not need children's credentials, birth dates, payment-card information, SMS history or mailbox access. Account connection and basket execution are restricted to personal accounts aged 16 or over; managed shared displays cannot operate them. Clearing another member's left shop (20 October 2026) is narrower: only an adult whose age is on record as 18 or over can do it. Young-member AI consent is checked before model selection.

The three new records, and the marker (added 7 October 2026).

Kind Whose Children's? Sensitive? Free text?
shopping_runs: the retailer, the store label the member already chose, a status from a closed list, how many items were wanted and how many are in the cart, when it started, was last updated and finished, and which member is running it the member running the shop; readable by every active member of their group yes, where a child account is one of those members no no — the status is a closed list and the store label is Woolworths' own store name and mode
retailer_price_observations: the catalogue ingredient the item came from, the catalogue meal plan or pantry entry it came from — never the group's own copy of a plan — the retailer, the product as Woolworths names it (its pack size only as part of that name, never a field of its own), the price seen in the cart, the quantity that price covers, the budget/standard/premium setting, and the calendar date nobody's — the row names no group, member, store, shop or task no the product is Woolworths' own catalogue words, pack size and all, and some products — a pharmacy line, an infant formula — say what somebody needs; the row says nothing about who no — the ingredient word is one of ours, from our recipe catalogue or our pantry list, never one a member typed
shopping_match_decisions: the same catalogue ingredient and retailer, the products that were offered with their prices and availability, which one was chosen, which were not, the quantity, the setting, one reason from a closed list, what verification found, the calendar date, and (since 30 October 2026) which step of our search found it as a code from a closed list, with an alternative's place as a small number nobody's, on the same terms no the same way, and for more products: every option that was offered is named, not only the one that went in the cart no
The marker on a shopping item: which catalogue meal plan or pantry entry it came from, the ingredient, the quantity and unit, and the title it was written for the group's, inside the item it belongs to yes, as any shopping item is an item can name a child's dietary or health need, as it could before yes — the ingredient and the title are words

What is not collected, and could have been. Neither new price nor decision record carries a group, a member, a store, a shop, a task, a time of day, or a word a member typed. There is no column for any of them, so the question is not what we remember to leave out. The group's view of a shop carries no item word either: the group can already see the items on its own lists, and the status adds nothing about them. No credential, card number, address or page ever reaches any of the three. The marker is the only new place words are stored at all, and section 3 sets two conditions on it.

One identifier is a readable name, and stays readable (added 7 October 2026). Our pantry list identifies an item by a name rather than a number — "pantry:olive oil" — so wherever something points at a pantry entry, that pointer is a word anybody can read: in the marker on a shopping item, and in the two de-identified tables, where it is that same name and not an opaque number. Identifiers in an item's structure are not sealed, and this one is not either, so it can sit beside a sealed title holding the same word. We say that plainly rather than leave it to be found, and we are not treating it as a new disclosure, because a group's own pantry record already stores exactly this name in plain text, beside the shopping task it created, and has since that record existed.

It does mean the two conditions in section 3 buy different things in the two cases. For an ingredient from one of our recipe plans, the plan is identified by a number and the words are sealed, so sealing them is what keeps the item's words out of readable storage. For a pantry staple, the item is named in the clear either way — as it already was before this change — and sealing the marker's words keeps the marker from adding a second readable copy rather than making the staple private. The sealing condition covers what somebody typed; it was never going to cover the names we file things under.

What Shopping's own records hold, and what goes to the judgment service (added 10 October 2026). None of this is built; the rows are described as this assessment requires them to be.

Kind Whose Children's? Sensitive? Free text?
shopping_lists and shopping_items: a list's title and an item's words, sealed under the group's key as the task rows they are copied from are; and, as fields of the item, how much of it, in what unit, which aisle it belongs in, whether it is ticked, who ticked it and when, its assignment, the provenance marker described below, and the times it was created and last changed the group's, readable by its active members, as the rows they came from were yes, where a child account is a member an item can name a child's dietary or health need, as it could before yes — an item's words are what a member typed, and they stay sealed
The frozen copies: for the weeks between the release and the clean-up, the rows the items were copied from, holding the same ciphertext and the same wrapped keys, writable by nobody; after the clean-up, only a list's own row that a member made one of their plans or linked to a goal (section 9) the group's, on the same terms, and readable by nobody new yes, on the same terms the same way yes, sealed, and a second copy of the same words
What the judgment service receives: the words of the item being typed, the words of the few candidates our own matching has narrowed to, the fragments of a comma list, and the app's own closed list of aisles — with the group's member and baby names replaced first nobody's to keep; one request and one answer, stored by us only as the counts and cost of the call words a child's carer typed can be in it; a child's account sends nothing yes — a food can say what somebody needs, and a typed phrase can name a person yes, and it is the whole point of the question
The remembered aisle: for a group, the aisle chosen for an item name, the name held sealed under the group's key as the item's words are, and when it was last used the group's, readable by its active members yes, on the same terms an item name can be sensitive, which is why it is sealed yes, sealed

What becomes readable that was not, and what does not. An item's words do not move: they are the same ciphertext under the same key, and our servers can read no more of them after the change than before. What becomes readable is the structure the app needs in order to sort a list and add a quantity up — how much, in what unit, which of the app's aisles, ticked or not, and by whom. That is where the line between a payload and a state sits everywhere else in the app, and these are states. A quantity a member types inside the item's own words stays inside those words; the fields hold what the member put in the fields for them, or what one of our own plans stated.

And one thing stops being recorded. Ticking an item is recorded on the item and writes no row to the group's task-completion history, so a group stops accumulating one row per member per grocery item, and nothing in the motivation layer counts a grocery tick. Grocery ticks already in that history stay there and stop being counted. The cost is that Shopping shows no history of who ticked what beyond the item's own last tick, which we think is the right way round for a shopping list.

3. Flows and locations

Shared item words retain the existing group content encryption and privacy rules — the rules their task rows follow today, and the same keys and the same per-group reading in Shopping's own tables after the change assessed on 10 October 2026. No new readable copy of a member's own words is made on our servers — a statement the 7 October 2026 changes keep only because of the two conditions on the marker below and because the ingredient word in a price record always comes from our own catalogue; both are the reason those conditions are written as requirements rather than preferences. Local shopping preferences and progress use device secure storage, scoped by group and member. Progress remains writable after the phone has first been unlocked since restarting, so locking it does not prevent a running shop from recording its result. It is never migrated to another device. Retailer browser traffic goes directly from the phone to Woolworths and its authentication services. The retailer processes it under its own policy; our Australian processing configuration does not control the retailer.

The phone searches Woolworths for each selected item. A bounded product-selection request sends that item's words, the amount on the list when the words state none, the member's budget/standard/premium preference, and up to 24 rendered product cards (product number, name including pack size, price and availability) to GroupApp's Australian service, which asks the models in turn set out under “Choosing a product: Jev first, then Flash, then Flash-Lite” below (28 October 2026): TypeSafe's Jev in the United States first, only where the member is eligible for it and the item names no dietary need or allergy, without the product numbers; then Gemini 3.8 Flash through Vertex AI at its global endpoint, which may process outside Australia, with Gemini 3.7 Flash when 3.8 has no capacity; and Gemini 3.5 Flash-Lite at the same endpoint last, only when neither Flash gave a usable answer. From 14 to 28 October 2026 Flash-Lite was also sent the request whenever Flash had not answered within about five seconds, and the first answer was used; that no longer happens. Product matching can involve dietary or health information already written in an item. No full page, login field, cookie, address, verification code, review or advertising text is sent, except as “When the shop's own reading fails” below allows. Since 31 October 2026, when the products were found by one of our catalogue's own search terms rather than the item's words, the request also carries that term, so the models can tell that, say, “Spring Onions Bunch” is the list's “green onions”; the term is our catalogue's words, never a member's. It is not kept in any log, table or crash report, and a shared run's record shows it only in the model steps' prompts, beside the search that already names it. An item is not sent to Jev when that term names a dietary need or an allergy, even if the item's own words don't. The model selects only from those observed products; deterministic code checks quantities and executes a closed set of browser actions on the phone. Unknown units or uncertain matches no longer pause the run (13 October 2026): the item is left out and the shop carries on, and the member sees each such item with up to three of the observed products — the model's suggestions first, then the page's own in Woolworths' order (28 October 2026) — and can confirm one, choose another on Woolworths' search page once the shop ends, or leave it on the list. A product check that gets no answer is tried once more and then treated the same way, and so is a search page that never answers, once. Suggestions are kept only on the phone, with the run, and nothing is added until the member confirms. From 28 October 2026 a confirmation made while the shop runs is added in that shop, and every product goes in the cart as soon as it is chosen (“Adding each product as it is chosen”, below). Ordinary chat additions retain their existing consent and privacy rules.

The member chooses a pickup or Direct to Boot store from a picker, or types a delivery address, before a run. A chosen store is saved on this phone until the member changes it or disconnects; a delivery address is saved only when the member ticks that choice. Until 7 October 2026 these values stayed on the phone and went only to Woolworths through its page. From the change assessed below, the chosen store's label — Woolworths' own store name and whether it is pick up or Direct to Boot — is also written to the group's view of the shop and read out in the group's daily brief, because telling the group where the shopping is happening is the point of that view. A typed delivery address is not: where a member has chosen delivery the status says only that, there is no column for an address, and no address reaches the brief; a page shown to the model can include one as “When the shop's own reading fails” below allows. Shopping does not select a time or enter checkout. Its phone-side controller recognises a closed set of sign-in and location controls; unknown or ambiguous pages pause. The model receives neither the address or store name nor credentials, codes, raw labels, page text or URLs, except as “When the shop's own reading fails” below allows. It cannot choose a browser action of its own. From 7 November 2026 its answer may ask for one more Woolworths search, with a term the app checks and builds into Woolworths' own search address, or for the product page of one product it has already been shown, which the app opens at Woolworths' fixed product address for that product number. For product selection, it never supplies an address, a page element, text to type or a script, and never chooses to add, remove, sign in, change the store or go near checkout; the page-reader exception below permits only an element number. A page's instructions, including prompt injection in product names or controls, cannot grant a new browser capability.

Reading Woolworths' location dialog for the store picker (added 6 October 2026). This is the "broader page interpretation" section 9 names as a review trigger, and this paragraph is that review. To show the picker, the phone's controller types the member's suburb or postcode into Woolworths' own location dialog and reads back at most 8 suburb suggestions (80 characters each) and at most 20 store rows, each a store name (80 characters) and which of pick up or Direct to Boot it offers. If the member chooses on Woolworths' page instead, the controller reads back the store name and mode from the page's location label. The phone checks every count, length and mode before use. These values are shown only to that member, saved only as the store they choose, never sent to the model and never added to the optional shopping record. Opening the dialog can need the member to be signed in to Woolworths first; the picker then sends them to the Woolworths page to sign in. The picker never saves a location on Woolworths itself; the run sets and checks it.

A device-local note that this member was signed in to Woolworths on this phone the last time is kept to show whether the basket is ready to start. It holds no credential, says nothing about the current session, and is cleared by Disconnect or when another member uses the retailer browser.

The service verifies active group membership, a personal account, age and young-member consent, and the current group and personal privacy settings before calling the model. Device-only or unreadable settings refuse model selection. Each request has input and output bounds, one time limit for the whole request, the existing assistant token and spend ceilings, and rate limiting. Since 28 October 2026 (below) a Vertex AI request may be tried again and may move from 3.8 Flash to 3.7 Flash and then to 3.5 Flash-Lite, and its first step may be TypeSafe's Jev. It never goes to any provider other than those two. As with other assistant requests, an unavailable bookkeeping service does not itself block a model call; a returned budget refusal does. Provider time and output bounds remain. Cancelling stops further browsing and discards any late answer; a request already sent may still incur a charge.

Credentials and codes do not enter chat, analytics or diagnostic event payloads. Browser event messages contain bounded status and product quantities, not page HTML. Disconnect clears the retailer's website data and local run state. Android clears GroupApp's embedded-browser cookies and website storage because it cannot completely enumerate one site's authentication cookies; this can also sign out another page opened inside GroupApp. It does not clear the phone's separate browser or retailer app. Signing out or changing the member stops execution. Clearing a local session does not cancel an order or revoke a session on another device.

Retailer-owned sign-in, revised 10 November 2026. The member signs in on Woolworths’ own page inside GroupApp, both during setup and when a shop needs help. There are no GroupApp email, password or verification-code fields, no saved-password shortcut and no credential filling. The phone may offer its own password-manager or one-time-code autofill; GroupApp requests no mailbox or SMS permission. Sign-in is detected from visible signed-in markers on the permitted retailer origin, never from a URL or a store/time panel alone. Creating an account, changing a password, accepting terms, security challenges and sign-in remain the member’s actions; GroupApp makes no purchase and checkout stays blocked.

The page expands in place with Back to GroupApp, the actual host, a task line and a dock. The same mounted browser and retailer session continue through sign-in, handover and return. While the member has the page, or a sign-in, challenge, page or location pause is waiting, the only injected scripts allowed are the reviewed session inspection and checkout boundary. Inspection reports closed step labels and a rejection boolean with request identifiers; unknown reply fields are rejected. Scripts never read password, email, username, telephone, one-time-code or card-field values, and install no input, key or change listeners. Text and image fallbacks are refused while the member has the page, on authentication hosts or on pages where their checks find sensitive fields. Late replies are checked against the current pause and controller, and an ownership revision revokes delayed DOM actions. A member can explicitly hand a product page back for the existing local product inspection; its result is shown in GroupApp before saving, rather than reading it while the member is operating the page. The store picker’s bounded replies described above remain separate from sign-in inspection.

Closed shadow roots cannot be inspected by page JavaScript. The text serializer excludes field values and does not traverse closed roots. A screenshot could still contain their contents. The founder accepted this residual on 10 November 2026 with an explicit disclosure and policy acknowledgement before capture. No claim is made that a DOM inspection can prove a screenshot safe. Real sign-in, autofill, keyboard, screen reader, Android Back and session continuity checks on iPhone and Android remain before release.

The on-phone browser stays mounted behind an opaque GroupApp surface during automatic work. The member can reveal the same page when help is needed or to inspect progress. This is hidden presentation, not a claim of reliable headless WebKit execution under every OS condition. A request for input, or a product to check, pauses native work and uses the existing generic shopping notification when the member is away. Continuing is another explicit user gesture. Time spent paused for the member doesn't count toward the 30-minute run limit. A stopped run never resumes itself. If the phone ends background work on a shop that is still going, the shop pauses: nothing more goes in the cart, and it continues only when the member returns and taps Continue, once the app has checked that the member, the group, their eligibility, the group's privacy setting, the shop's status, the Woolworths sign-in and the cart still hold. Otherwise it ends. A pause like this ends after two hours.

If iOS declines continued processing, a run may proceed only while GroupApp is open, with that limit shown beside its controls. Backgrounding stops foreground-only execution, clears pending credentials and reports incomplete work. A run already paused for input may stay paused while the member retrieves a code; continuing requires a new gesture, and the paused time is not counted against the run. Cancellation while native startup is pending never becomes a foreground retry. This fallback adds no data flow or permissions.

The optional journey trace records the broad connecting, input-required and resumed milestones. Since 13 October 2026, each time a run stops to ask the member for something it also records what was asked for and why, as codes from two fixed lists: for example that Woolworths asked for a one-time code, refused a password, needed a store chosen, or that a product needed choosing because the search found nothing. No field value, typed word or page enters it. A run's ending likewise records a code for why it stopped and the stage it reached, and the run's record names the app release and platform, with nothing that identifies the phone.

When a Woolworths page doesn't read as expected (the product tiles have changed, a search or cart step stalls, or Woolworths shows a block or security page), the phone sends GroupApp's server a code for which of those happened, with the app release and platform. Nothing about the member, the group, the items or the page goes with it, and it is sent whether or not the run is shared. The server writes it as one log line so the team is alerted to fix the reader. Since 30 October 2026, when a run ends the phone likewise sends how many of its product checks Jev decided, passed on, or wasn't asked, with the run's item count, product preference and the app release: counts and codes only, nothing about the member, the group, the run or the items, whether or not the run is shared. The server writes it as one log line, so the team can see how often Jev decides in a shop. A shared run's record carries the same counts. If the product tiles have changed, the phone reads the same four product fields from the page's product links instead: no more of the page leaves the phone than before. To confirm what it added, a shop now opens Woolworths' cart panel once at the end and reads each line's product number and quantity on the phone; only the lines for this shop's own products are used, and none of it is sent anywhere. It stays the same run across an input pause. An OS-killed run is reported incomplete on return.

Removing saved sign-in on this phone (10 November 2026)

The earlier optional saved-password and remembered-email feature is removed. On update, account change, sign-out and Disconnect, the app attempts to delete the old email, password and preference keys without reading their values. It covers the current account, the previous account available during a switch, the recorded retailer-browser owner and identities in its retry metadata. Deletion is idempotent. A failed account remains queued; subsequent launch, return to foreground and account events retry. Retry metadata contains only account IDs. A failed initial metadata write is retained in memory for retry; a device that cannot persist any metadata and is then killed cannot provide durable retry evidence for that new identity. The app never writes a legacy credential key again. This removal does not clear retailer cookies; Disconnect and the existing change-of-browser-owner protection still clear the retailer session.

Residual: SecureStore does not provide a key-enumeration API, and earlier versions kept no complete account index. Old keys belonging to an account absent from the current identity, browser-owner record and retry metadata cannot be proven deleted. An old account encountered again is added to cleanup, but the app does not claim every orphaned saved copy is gone. A keychain failure can also delay deletion; no secret is read or logged to diagnose it.

Cart runs, the group's view of a shop, observed prices and the matching choice (added 7 October 2026)

Written before the code, and read back against it on 7 October 2026. Three sentences in this subsection were changed in that pass and are marked where they stand: who writes the two de-identified tables, how a repeated write is absorbed, and how many sentences the brief has.

Filling the cart. A shop adds products to the member's own Woolworths cart and nowhere else: there is no retailer list to create, name or save, and no step that reaches checkout or payment. Before it changes anything the phone reads how much of that product is already in the cart, and an item is marked off in GroupApp only when the phone has verified that the quantity it needed went in. When the shop ends, the handoff is the same link to Woolworths' app as before, relabelled Open Woolworths cart; Woolworths' own app opens at the page where that cart is reviewed. GroupApp does not order and does not pay. That the app opens at that page has still not been seen working on a phone, and the new label does not make it verified.

The marker on a shopping item. A shopping item generated from a meal plan, or a pantry staple added by Pantry Check or Quickly add staples, carries a small structured marker naming the catalogue ingredient behind it, the plan or pantry entry it came from, the quantity and unit, and the title the marker was written for. Nothing is ever inferred from a title: if the words of an item are later edited, the stored title no longer matches, the phone can see the item is not the ingredient the marker names, and the item is excluded from price recording without anything reading or judging the new words. Two conditions go with it, and they are what keeps the statement in the first paragraph of this section true:

  1. A marker is written only where it can name something of ours — an entry in our recipe catalogue or in our pantry list. A plan a member wrote themselves, whose ingredients are their own words, carries no marker, and its items are never priced.
  2. Any word the marker holds is sealed with that item's other words, under the group's key, the way the item's title and note already are. The marker must not become a readable copy, beside a sealed title, of the same words the sealing exists to cover.

The group's view of a shop. Starting a shop writes a row holding the retailer, the store label, a status from a closed list, how many items were wanted and how many are in the cart, the times it started, last changed and finished, and which member is running it. Every active member of the group can read it, through the same per-group database rules that already govern their tasks. Only the member running the shop can write their own row, with one exception added on 20 October 2026. If a shop has been left, another adult in the group can clear it through one database function. A shop counts as left when, by the server's clock, it has gone 30 minutes without a change while running or waiting, or 6 hours while ready. The adult must be a person (not a shared display or a profile), an active member, 18 or over with their age on record, and signed in with two steps. Clearing marks the shop cancelled and records when. It records nobody's name, so the member is told their shop was cleared from another phone, not by whom, and nothing is said in the group chat. The person clearing learns nothing they couldn't already read in the row: no item, no product and nothing from Woolworths. A second active shop for the same group and retailer is refused by the database as well as by the screen. It holds no credential, no product and no item word. The group's daily brief turns it into one of two fixed sentences naming the member's first name, the retailer and the store, and nothing else — one while a shop is going, one once the member has finished it. A shop that is waiting to be finished draws neither, because neither would be true of it, and a shop that was cancelled or failed draws nothing at all. Writing it is best effort: if the write fails the shop carries on and the member is told their progress may not be visible to the others. Sign-in pauses, decisions to review and the Finish button appear only on the phone running the shop. The others see a status and, once a shop has been left, a way to clear it. The phone running a shop checks its row when the app opens or comes back, at each continue and when a status write finds nothing to change. If the shop was cleared, the phone stops adding at once and says so, so two people are never filling for the same lists. Finish still marks off what that phone verified in its own cart, but it can't reopen the cleared shop or give it the brief's completion sentence.

Prices observed in the cart. When a shop has verified that a product went into the cart, and only then, the phone may record what that product cost. A record holds the catalogue ingredient, the catalogue plan or pantry entry it came from — our own recipe plan, never the group's adopted copy of one — the retailer, the product as Woolworths names it (its pack size only as part of that name, never a field of its own), the price, the quantity that price covers, the run's budget/standard/premium setting, and the calendar date in the group's own time zone. It holds no store, group, member, shop, task or typed word, and no time of day — a calendar date is enough to compare what a plan costs from week to week, and a timestamp would say when a particular member went shopping. These are prices observed in one cart, at one store, on one day; they are not a price list, and in this change no screen shows a price to anybody.

No member and no group is granted any way to read the table, so the rows are not a group record that anyone could look up. Who writes them changed between this draft and the code, and this is the corrected sentence. The design said our own shopping service writes them with a privileged key no phone holds. That server is deliberately not given such a key — keeping it away is what makes a breach of our cloud provider survivable — so the write is instead one narrow database function per table, reached through that server, which re-checks that the caller is a real person, not a shared display, not an account under 16, signed in with two steps, and a member of some group. Any signed-in member could call it, so "only our service writes these" is practice rather than proof; section 6 sets out why nothing in the argument above rests on it, and residual 5 accepts the consequence. A repeated attempt is absorbed by the row's own unique key rather than creating a second row.

An item qualifies only when its marker names something of ours, the product and price were verified in this shop, and the quantity the plan accounts for can be worked out — for an item that combines a plan's need with somebody's personal addition, only the plan's share, and nothing at all when the two cannot be separated. A personal addition has no marker and never qualifies. Every part of that test is made from the marker and the numbers, never from the words of an item.

De-identified is not anonymous, and we do not claim it is. A row names nobody, but somebody holding both our database and the knowledge that a particular group cooked a particular plan on a particular day could associate a row with that group. What the row would then tell them is what a supermarket charged for a food that day. We think that is a fair trade for being able to tell a group later what a meal plan costs; section 8 states it as a residual rather than hiding it here.

The matching choice. Help improve product matching is a switch in Shopping's settings, off until a member turns it on, kept on that member's own phone and applying only to shops they run. Its words say, beside the switch, that eligible prices are recorded during a shop either way — so that nobody turns it on believing it is what starts that, or off believing it stops it — and what the switch itself adds: a structured record of each product decision in the run's own 14-day record, and a de-identified copy kept by us for longer, in shopping_match_decisions.

A decision holds the ingredient and retailer, the products that were offered with their prices and availability, the one chosen, the ones that were not, the quantity, the setting, a single reason from a closed list, and what verification found. No credential, payment detail, address or location is in the shape at all. The de-identified copy is written under the same test as a price record — only for an item whose marker names something of ours — so an item a member typed never reaches it, and the table has no column that could hold a typed word. The copy in the run's own record covers the whole shop, as that record already covers every step of it, and it exists only where the member has also ticked the existing per-run sharing choice, because without that choice there is no record to add to. The product names in a decision are Woolworths' catalogue words; some of them — a pharmacy line, an infant formula — say something about what a person needs, and they sit in rows that name no person.

Since 28 October 2026 a decision also says who chose and what Jev would have chosen (founder's decision), so we can tell whether Jev's pick below the cut would have been right: which model answered — Jev or the Gemini model, by name — and, when Jev named a product, that product's number out of the ones offered and Jev's probability for it, to two decimal places; when Jev said none of them fits, its probability for that alone. Both are ours or Woolworths': a model's name, a product number already in the decision, and a number. Neither is a word anybody typed, and neither names a person, so the rule for this table holds unchanged. Our service and the database each refuse a product number that was not one of those offered.

Since 30 October 2026 a decision also says how our search found the product: which step of our search found it, as one code from a closed list (the item's own words, our catalogue's first search, one of its alternatives, a substitute, a gluten-free brand option, the model's own re-search, a saved choice or the member's pick), and, for an alternative, which of our catalogue's alternatives it was, as a small number. Both are ours: our catalogue's steps, never a word anybody typed. A gluten-free brand option is reached only from an item our catalogue already names as gluten free, so the code says nothing about a person that the row didn't already say. Retention is unchanged: no end date in this table, and 14 days in the run's own record, where the same code sits beside the search it describes.

The Arrange pickup task. On the way into a shop the member may ask for an ordinary group task, titled "Arrange Woolworths pickup", or "Arrange Woolworths delivery" for a delivery shop, due that day in the group's time zone, with a note asking that person to check the cart, pick a time and place the order in the Woolworths app, and naming whose Woolworths account the cart is in. It is assigned to the member shopping unless they choose another adult with their own account: never a profile, the wall or a member under 18, and only the member shopping while the phone can't tell who is under 18 (revised 26 October 2026). It is sealed and visible like any other task. Its words never say that an order, a time or a booking exists, because none does. It is not offered to an account under 16: the same line that stops a child running a shop stops a child being asked to place the order.

Shopping's own lists and items, the move and the frozen rows (added 10 October 2026)

Written before any of it is built. Nothing in this subsection describes something working.

Where a list lives. A group's shopping lists and the items on them become rows of their own. An item's words — what it is, and any note on it — are sealed under the group's key by exactly the key scheme its task row uses today, so what our servers can read of a member's words does not change. The fields beside those words hold the quantity, the unit, the aisle, whether the item is ticked, who ticked it and when, and the item's assignment. Our servers cannot fill those fields from a member's words, because they cannot read them: the phone writes them, or one of our own plans states them, or they are empty. (C3)

The move. At the release, one database change, in one transaction: the new tables are created; every existing item row is copied with its ciphertext and its wrapped keys exactly as they are stored, the same identifier, and the times it was created, last changed and ticked, and by whom; the pantry's own pointer at its shopping row (group_pantry_items.shopping_task_id) is re-pointed; steps filed under any other kind of task become ordinary tasks; and every copied row is marked moved. Nothing is opened to move it. No key is unwrapped, no word is read, and no plaintext of a sealed item exists at any point — a copy that carries the ciphertext carries none of the words, which is the only reason a change of this size can be made to a group's own content by servers that cannot read it.

The frozen rows. The same transaction installs a rule that refuses any insert, update or delete of a moved row, and any new insert of the old item-under-a-task shape, from every version of the app. Copying and freezing together leave no gap, so there is no window in which a write lands in rows that have stopped being read, and no reconciliation afterwards. From that moment the new tables are the only authority.

A queued write from before the upgrade. A phone that was offline when somebody added an item has that write waiting in its own queue. It is replayed as an insert on the list it was meant for; if that list cannot be found, it is shown as failed and keeps the words for the member to put somewhere. A queued write of a member's own words is never dropped and never re-sealed into anything weaker, which is the rule everywhere else the app queues a write.

A basket prepared before the move. A shop saved on a phone before the release still resolves after it, because every item keeps its identifier; Finish ticks the same items in their new table. Keeping the identifiers is a condition of the copy rather than a convenience: minting new ones would leave a member's prepared basket pointing at rows that no longer exist, and the only recovery would be shopping again.

Our own assistant server's shopping writer is in place before the release and off until it, so only one shape is ever live and nothing writes to both. That server holds no key that can read a group's words, before or after, and this change gives it none.

Choosing a product: Jev first, then Flash, then Flash-Lite (added 28 October 2026)

Written before the code, and accepted by the founder on 28 October 2026, with its residuals below. Condition C6 below is met by privacy policy v3.14-2026-10-28. The rest of the chain sends nothing to anybody new.

Revised the same evening, on the founder's decisions. The TypeSafe step is on by default: a release turns it on with no setting, and setting shopping_decision_jev_enabled to false in our infrastructure configuration turns it off without a release. It is used only at a probability of 0.9 or more, which is above anything our first experiment placed (below). A second experiment compared shops with Jev on, as the baseline, against Jev off, preference by preference, by a rule written down before it ran. Every gate below still applies to each request.

Revised again on 29 October 2026, on that experiment's result and the founder's decision. The second experiment asked Jev about 150 items at every preference. At 0.9, Jev chose a product whose name didn't confirm a dietary requirement on three items — a coconut yoghurt for "dairy-free yoghurt", plant-based mince and sausages for "vegan" — and by the rule that turned every preference off. Leaving out items that name a dietary need or an allergy, which the step already does, the rule held at every preference. The founder chose that: Jev is asked for Basic (budget) and Standard products only, never Premium, and never for an item naming a dietary need or an allergy. At Basic, Jev decided 44% of the other items, one of 53 wrongly. At Standard it decided 16%, one of 19 wrongly: fewer than the 30 items the rule asks for, so Standard is on but not confirmed, and it is watched through the record of what Jev would have chosen (below) on real shops. At Premium Jev decided 6%, too little to justify a second processor.

Revised again on 31 October 2026, from that experiment's own answers, with no new calls. Jev's pick is used only at a probability of 0.95 or more. In the second experiment Jev made no wrong pick at 0.95 or above, and its only wrong pick above 0.9 was a plain feta for "Greek feta", at 0.93. Jev now decides about a quarter of items at Basic and about one in ten at Standard; the rest go to Gemini. And a product chosen for an item that names a dietary need must say so in its name, whichever model chose it: "gluten free" (or "free from gluten", or "GF" as a word of its own) for gluten-free, "dairy free" for dairy-free, "vegan" for vegan, "halal" for halal, and so on through a fixed list. An allergen counts as a need when the words around it say so — "free", "allergy" or "low" after it, or "no", "not", "without", "avoid", "free of" or "can't have" (with or without the apostrophe) shortly before it — and every allergen in a list ("nut and dairy free", "free of milk and nuts") is a need of its own, each to be named. When such words reach a food that isn't on our allergen list ("no pork", "almond free", "no egg or pork"), the member is always asked. An allergen the item simply names as food ("peanut butter", the soy sauce in "gluten-free soy sauce") is not a need. Spacing, dashes, symbols and invisible characters are read alike. A product's name lists several needs only with "&" or "and", and only at its start ("Egg & Dairy Free Cake"), so "Bacon, Egg & Gluten Free Quiche", "Choc Nut & Gluten Free Bars" and "Choc Nut / Gluten Free Bars" count as gluten free only. A name that says "contains", "traces", "not" or "non" never counts, and a need with no confirming phrase on the list (keto, plant-based, milk-free, an allergy written out) always counts as unconfirmed. Otherwise the member is asked, as for any unclear match, and can choose from up to three of the page's products after checking the label; one of them can be the product the check turned down. In that experiment, this check would have turned all four of Gemini's unsafe dietary picks into questions — a coconut yoghurt for "dairy-free", plant-based sausages for "vegan", an onion and garlic free passata for "low-FODMAP" and a "no added sugar" syrup for "sugar-free" — and kept every right one. Nothing new is sent to anybody or kept; fewer automated choices are made.

Why it changed. On a real shop on 28 October 2026, 7 of about 16 product choices were answered by Gemini 3.5 Flash-Lite, the backup that started whenever 3.8 Flash had not answered within about five seconds. In our experiment of 14 October 2026 Flash-Lite asked the member instead of choosing on 10 of 54 checks where Flash asked on none, and the questions it asked on that shop had obvious answers. So Flash-Lite no longer races Flash. A product check now asks, in turn:

  1. TypeSafe's Jev, one choice question: which of the listed products is the item, or none of them. Its answer is used only when it names a product with a probability of at least 0.95 (0.9 until 31 October 2026). What the same experiment shows, said plainly: at 0.7, Jev picked a product 30 times, on 10 of the 18 items, and every pick was right; the other 24 checks went on to Gemini. 0.7 was chosen after the run; the experiment had fixed 0.5 in advance, and at 0.5 Jev chose wrongly three times. Ten distinct items with no wrong pick still allow a confident-wrong rate of about one in four, and the experiment asked every item at the standard preference only. 0.9 is a stricter cut than any it measured, so Jev will decide fewer items than it did there. A product it picks still passes every check our code puts any pick through: an observed, available product, a pack count our code can work out, and no more than $200 for one item. Anything else — "none", a lower probability, no answer in time, a pick our code refuses — goes on to step 2. Jev never asks the member anything, and never decides that an item should be put to them.
  2. Gemini 3.8 Flash, through Vertex AI's global endpoint, as before. When it has no capacity or does not answer in time it is tried once more, and then Gemini 3.7 Flash is asked at the same endpoint — the arrangement the assistant has used since 22 October 2026: the same processor, the same location and the same request with only the model's name changed. When Flash answers by asking the member, that question is the answer and is used.
  3. Gemini 3.5 Flash-Lite, at the same endpoint, only when neither Flash gave an answer our code could read: an error, no answer in time, or a reply in the wrong shape.

The whole chain fits inside one limit of 48 seconds from when our service receives the request, well inside the 58 seconds the phone waits, including the reads Jev's step makes first. A phone that doesn't ask for the longer wait keeps a limit of 18 seconds. A step that cannot start with enough of that time left is skipped, and a request the phone has stopped waiting for is cancelled. Before each model is asked, the member's and the group's allowances and our spending ceiling are checked again, after the step before was counted, so one step's cost can stop the next. No two models are asked the same question at once any more.

An item that names a dietary need or an allergy, or whose catalogue search term does, is not sent to TypeSafe. Our code looks for a fixed list of words, and such an item goes straight to step 2:

"Milk", "eggs", "fish" or "wheat" on their own are ordinary items and still reach it. The experiment had one confident pick on a restriction. Our code's own checks of a pick look at availability, quantity and price, and since 31 October 2026 at whether the product's name names the item's dietary need (above); that check reads names only, so it isn't a reason to send such items to Jev. A restriction written another way ("keep it away from Sam") still reaches Jev; that is residual 3.

The amount on the list (added 7 November 2026, written before the code). Accepted by the founder on [date]. When an item's words state no amount and its quantity and unit fields do, the phone adds that amount to the product check: a number within the field's own bounds and one unit from a fixed list of ours (such as g, kg, ml, L, tin, can, bunch, pack or each). A unit outside the list stays on the phone and the item is handled as if no amount were stated, so words a member typed into the unit field never reach a model, whoever typed them. The amount goes to Gemini through Vertex AI at its global endpoint. Our code also uses it to work out how many packs to add. From the product name and price it already has, the server also works out each product's size, format, unit price, pack count and total cost and gives those to the model; they add nothing of the member's. No search term of ours changes. Nothing new is kept: the amount is not in any log, table or status the group sees, and a shared run's record shows it only in the model steps' prompts.

The amount says a little more about a household than the words alone ("6 tins" of an infant formula). It travels only with the item it belongs to and only to recipients who already get that item's words. A list whose unit isn't on the fixed list gets no amount, so the pack count stays as it is today.

Price preferences and product variants (added 7 November 2026). Accepted by the founder on [date]. Derived fields are rebuilt from parsed numbers and fixed codes, inside the untrusted-data fence. A fixed-word variant check refuses conflicting meats, flavours and cuts. The amount does not change any dietary or health check, add a source for dietary needs, or reach TypeSafe in this change; its question is unchanged. Only already-gated product facts can inform specials or Health Star Rating. No health or taste benefit is claimed. A stated amount needs a known pack count and total, preferring aggregates within ±25% when a match fits, otherwise retaining existing pack rules, with kitchen measures exempt; powder yields are never inferred. With no amount, default pack sizes are preferred. Standard category upgrades are preferences within the price ceiling; if none qualifies, a valid matching pick remains automatic and only a closed tier-disagreement code is logged.

What is sent to TypeSafe, and what is not. The item's words, with the group's member and baby names replaced first by the pattern every other use of that service applies; the member's budget, standard or premium preference as a fixed phrase of ours; and the product cards the phone read from Woolworths' public search page — each product's name including its pack size, its price, and whether it is out of stock. Not the product numbers: Jev answers with a position in the list, and our code turns that back into a product. The product names are Woolworths' public text and are sent as they appear, because a product that shares a member's name is still a product. Since 31 October 2026, when one of our catalogue's own search terms found the products, a sentence of ours naming that term. For eligible note-bearing shops, the active shopping notes may also be sent as described below. No list, group or member identifier, store, address, conversation or unrelated record is sent. Item words can say what somebody needs — an allergy-free food, an infant formula — and are sent as they were written, as they already are to Google.

Where it is processed, and for how long. TypeSafe is hosted in the United States. It says it does not train on what it is sent; zero data retention is a separate enterprise provision and is not assumed here. We keep nothing of the request: each call is counted in the existing records of what the assistant costs — its model, token counts, timing and outcome — and never the words. It is counted against the member's and the group's weekly allowance like the Gemini calls.

Who it is used for. Only for a shop set to Basic or Standard products, for an item that names no dietary need or allergy, and only where the product check already runs — a personal account, aged 16 or over with a 16- or 17-year-old's own AI choice on, a group that is not Device-only, never the shared display — and only when, on top of that: the setting is on; our service can read who is in the group, so that every name can be replaced (if it cannot, nothing is sent to TypeSafe); and the member's own record shows they acknowledged a privacy notice that names TypeSafe for their shopping words. Anybody else gets steps 2 and 3 alone, exactly as before, and nothing tells them otherwise because nothing about their shop changes.

What the optional shopping record shows. With a run's "Help us improve shopping" choice on, the TypeSafe step appears in that run's record as a model step of its own, with its model, timing, token counts and outcome, and — as for every model step in the record — what it was asked and what it answered, with names replaced. That adds no new kind of content: the record already holds the item's words and the product cards, and the answer is a position and a probability. Which model answered each choice is noted on the choice. The record also notes, when a search page is slow, which of five fixed reasons it gave for not being ready; that is a code of ours, never page text.

Condition before the TypeSafe step is on (C6). The privacy policy's shopping paragraph says that an item's words and its product options go to Google's AI service, which picks a product. That stops being the whole truth the moment Jev is asked. The setting stays off until the policy names TypeSafe as a recipient of the words of an item being matched to a product, and the notice version our service checks moves to that policy in the same change. Until then, the notice it checks is the one that names a typed shopping item, which is narrower than this use. Met on 28 October 2026: privacy policy v3.14-2026-10-28 names TypeSafe in its shopping paragraph, its automated decisions and its list of providers, and SHOPPING_DECISION_JEV_POLICY_VERSION is that version.

Residuals to accept with this change.

  1. The words of an item being matched, and its product options, reach a second processor in the United States. Bounded to one item and the products found for it, with names replaced. The same service already receives a typed shopping item, and a typed request to add one.
  2. Names are replaced, and a phrase can still identify somebody. As for every other use.
  3. The cut is measured, but not on real shops, and Standard only thinly. The second experiment (29 October 2026) used invented product lists for 150 real catalogue items. Without dietary items, Jev at 0.9 was wrong on 1 of 53 items it decided at Basic (at most about 9% with 95% confidence) and 1 of 19 at Standard (at most about 23%). Its wrong pick was a plain feta for "Greek feta". With Jev off, Google's model made two of the same unsafe dietary picks Jev made. Since 31 October 2026 the cut is 0.95, where that experiment had no wrong pick, and a pick for an item naming a dietary need must name it. A restriction the word list misses reaches Jev. A confident wrong pick goes into the cart like any other pick, and the member still checks the cart in Woolworths before anything is ordered.
  4. There is no switch for this alone. The levers are the same as for tidying an item: the group's privacy level, or declining the assistant.
  5. A product name written to sway the pick reaches Jev as it is. The question is put to Jev in the wording the experiment measured, without the fencing a Gemini prompt has, so text in a product's name is read as part of the question. What bounds it: Jev can only answer with a position on the list our code built, and the pick then passes the same checks as any other — an observed, available product, a pack count our code works out, and no more than $200. A confident wrong pick lands in the cart, and the member checks the cart before ordering.

Adding each product as it is chosen (added 28 October 2026)

Written before the code is released, on the founder's decision of 28 October 2026, after two shops that day stopped while still choosing and left the member's cart empty.

Looking further for a product: more searches and one product page (added 7 November 2026, written before the code)

This is the "broader page interpretation" section 9 names as a review trigger, and this paragraph is that review. Until now the model saw one page of Woolworths' search results for an item (two at most), and picked from it or asked the member. From this change, when the first page has nothing that clearly fits, the model may instead ask for up to two more Woolworths searches for that item, with a term of its own, and for the product page of one product it has already been shown. Items found through our catalogue's own search terms can be searched again too, once those terms are used up. The app, not the model, decides whether there is time and budget left in the shop for each extra step, checks every term and builds it into Woolworths' own search address, and opens the product page at Woolworths' fixed address for that product number. The model never supplies an address, a page element, text to type or a script, and it still only chooses from products a Woolworths search showed for that item; the app still checks availability, quantity and price, adds the product and confirms it is in the cart.

What is sent. A search term the model writes goes to Woolworths from the member's own signed-in session, as the app's own searches already do. It must keep every dietary word the item has, may not contain a name from the group's lists (names are replaced before the item is sent to the model, and never put back), a web address or unusual characters, and may not repeat an earlier search. From a product page the app reads, without clicking anything, a fixed set of facts: size, unit price, price, whether it is in stock, whether it is on special and its earlier price if so, its Health Star Rating, and which of the allergens Australian labels must declare it contains or may contain. Where the item names a dietary need or an allergy, it also reads the ingredients line, up to 300 characters. These facts go to Gemini through Vertex AI at its global endpoint, which may process outside Australia, in the same transient request as the product options. No description, advertising text, reviews, ratings, links or other page text is read or sent. Nothing of this goes to TypeSafe's Jev, which still sees only the first page, as described above. An item that names an allergy still ends as a question for the member, as before; what a label says is used only to set products aside or to order the suggestions.

What the member sees. The model's short reason is checked by the app before it is shown: anything with a web address, a long number, or words about signing in, codes or paying is replaced with a fixed sentence.

What is kept. Nothing new on our servers: requests stay transient, with only token and spend counts. Operational logs get fixed step codes and counts, never a term, product, fact or reason. When the member ticks "Help us improve shopping", that run's record also holds the extra searches and the product facts exactly as the model saw them, under the same consent, recipients, 14-day retention and erasure.

Who. The eligibility gate is unchanged and checked on every request: no accounts under 16, a member aged 16 or 17 only with their AI choice on, no shared display, no Device-only group. Items a child wrote on a shared list can now meet up to four model requests and two more searches when an adult shops (section 7). The extra steps run only when the member's app has recorded that they saw the privacy policy describing them; otherwise, or when the setting is off, or anything fails, the item is handled as before.

Residuals we accept. More searches from the member's session mean more exposure to Woolworths' bot checks; a per-shop limit on extra searches and pages bounds it, and a block stops extra steps for the rest of the shop. Product facts are Woolworths' and may be wrong or out of date. Text on a product page could try to steer the model; it can at worst waste the item's extra steps, pick a different product it was already shown (which the app's checks still apply to), or shape the reason, which the app filters.

A member's name that is also a grocery word (such as Olive or Basil) is replaced in the item too, so that item is more likely to end as a question for the member.

Accepted by the founder on 7 November 2026.

Shopping notes (added November 2026, written before the code)

A group can keep a short list of notes for its shopping, such as "Free range eggs only": up to 10 active notes of up to 120 characters each. Any adult member of the group can add a note from the main shopping page or when they start a shop, cross one out when it no longer applies, and see who wrote it. The list is stored on our server for the group and every adult member of the group can read and change it. Children, managed accounts and shared displays cannot. A member who leaves, or whose account is deleted, takes the notes they wrote with them. A note crossed out is deleted after 30 days. Deleting the group deletes its notes. A member's export includes the notes they wrote.

What is sent. When a shop starts, the app copies the notes that aren't crossed out. For a product check in that shop the notes may go with the item to Gemini through Vertex AI at its global endpoint, which may process outside Australia, as a transient request, or to TypeSafe as described below. Names from the group's member and baby lists are replaced first; other names go as written. Crossed-out notes are never sent.

TypeSafe. With the shopper’s acknowledgement of the updated policy, eligible product checks may send active notes to TypeSafe’s Jev in the United States, with the same name replacement. Other names and identifying details may remain. Saved product choices are not reused in a shop with active notes. A member's own choice of product stands as they made it. If a note can't be sent with its names replaced, or another check fails, the item becomes a question for the member; it is never decided without the note.

What a note can do. The model is told a note is a preference and may use it only to rule out or rank products a search already showed, or to ask the member. It can't add a product, change a quantity or a limit, follow an instruction in a note, or relax a rule. Our checks don't read notes: an item's dietary, allergy and health handling, the pack count and the price check work from the item's own words. A search term the model writes may not contain a note's own words, though it can reflect what a note means, and the retailer sees that search from the member's own session.

Notes are preferences, not a safety check. Nothing checks a product against a note. A note with allergy or medical words gets a warning and can still be saved; the warning says who can read it and that the app does not check products against it. The member should write the need on the item, where the existing rule puts that item to them as a question.

Which note changed a decision. Gemini may answer with the note's number, never its text. Our code checks the number and the app shows the note beside the product or question to adult members of the group. This is the model's own report; our code can't confirm it. Jev does not report which note changed a choice, so an absent note attribution does not mean the note was ignored. It isn't in a notification or Live Activity.

What is kept. The notes on our server (above). Operational logs get counts at most. Shops with active notes add no rows to the de-identified match decisions. When the member ticks "Help us improve shopping", that run's record also holds the notes as sent, their count, and the numbers the model reported, under the same consent, recipients, 14-day retention and erasure. Notes already in a record are not removed when the note is deleted from the group.

Who. Adults only, checked on every request and by the database: no account under 18, no managed account, no shared display, no Device-only group. It works only when the member's app has recorded that they saw the privacy policy describing it.

Residuals we accept. Any adult member can write about another person, including a child, in words our list doesn't catch, and a name not on the group's lists is sent as written. A health note is stored for the group, shown to adults, and may be sent to Google or TypeSafe; nothing checks products against it. Another adult's note can steer the shopper's AI, and the shopper may see which note the model reports affected a choice. A note can make the model ask more often, or choose less well.

Assess this again before notes are offered to anyone under 18, read by any additional check, or shown outside the group.

Per-product Jev questions (10 November 2026)

The founder directs that Jev v2 be enabled for eligible shops before the planned paid experiment. When active notes may be sent under the separate notice gate, Jev also assesses them as untrusted preferences for each candidate. It reports whether it can consider them; uncertain or malformed answers fall through to notes-aware Gemini or review. Its confidence is a model output, not proof that it understood a note or checked a product for safety. Instead of asking Jev to pick a position from a list, the service sends one yes/no question for each available product in a single request of at most 12 questions. The request contains the item, its stated amount, an applicable catalogue search term, and each product name, format and size. It does not send the shopping tier or product prices to Jev. Names from the group's member and baby lists are replaced first. Our code applies the tier, price, amount, variant and product checks to the answers; only answers at or above 0.95 can be used. An insufficient or unreadable answer falls through to the existing Gemini or member-review path. The existing per-request admission, spend limits and cancellation apply. When a member has separately opted into the shopping record, its existing model step records these questions and their answers with names replaced, in place of the previous choice answer.

The 0.95 cut is provisional: the wrong-pick rate for these per-product questions is unknown, including on real shops. The earlier experiment and its results above measured the previous question and cannot establish this rate. A confident wrong product can still be added to the cart; the member reviews the cart before ordering. The founder wants retrospective real-shop evidence later, but this change adds no monitoring fields, data access or replay. Existing closed-code and count telemetry does not by itself measure wrong picks.

The age, consent, disclosure, dietary, amount and roster checks remain in force. A shop with active notes may send them to Jev only after the updated notice is acknowledged; if the note snapshot or its access checks cannot be verified, the route refuses rather than treating it as empty. The founder approved this change to N7 on 10 November 2026. N8, N9 and N22 continue to apply. Setting the v2 switch to false returns eligible no-note requests to the previous Jev question; the global Jev switch disables both versions.

When the shop's own reading fails (added 8 November 2026, written before the code)

This is the "broader page interpretation" section 9 names as a review trigger, and this paragraph is that review. When the app's own reading of a Woolworths and Coles page fails its self-check, for example tiles but no Add control, the app may send that page to Gemini through Vertex AI at its global endpoint. That endpoint may process outside Australia. It is the same processor, location and terms as product selection. First it sends a numbered list of the page's controls and their visible text. Only if that fails does it send one screenshot of the in-app retailer view. Both can include the member's name, email, delivery address, store, cart contents and Rewards details as the retailer shows them. Cart lines can reveal health needs. The founder accepted this on 8 November 2026 because a shop that stops is worse for members than this exposure. The app does not intentionally capture sign-in, verification, checkout, payment or order pages, or pages the member is controlling. It checks for password, code, card and other editable fields and refuses capture when it finds one. These checks cannot inspect every closed shadow root or cross-realm field. A screenshot may therefore include hidden sensitive information, including passwords, verification codes, payment details or typed values. The founder accepted that residual on 10 November 2026 with an explicit policy notice and acknowledgement before capture. Nothing goes to TypeSafe's Jev.

The model returns only an element number, or a point the app maps back to an element. The app checks every click with the existing click guard, quantity cap and checkout boundary. The model never supplies an address, a script or text to type.

What is kept: nothing on our servers or the phone beyond the request, only token and spend counts and anonymous reports of the retailer, page kind, failed rule, fallback level, outcome, app and bundle versions, and a sanitised structural outline with no page text, labels or identifiers. With "Help us improve shopping" on, the same fields are included as metadata in that run's record. The screenshot is held in memory for the request and never written to disk, a log, a crash report, a table or the "Help us improve shopping" record. Google: request-response logging is off for these models in our inference project, durable caching is off, and the in-memory cache lasts up to 24 hours. A request flagged by Google's abuse classifiers may be kept up to 90 days. Google's terms say it does not train on it. We make no zero-retention claim.

Who: the product-selection gate is checked on every request. No one under 16, a 16 or 17-year-old only with their AI choice on, no shared display, no Device-only group. It runs only once the member's app has recorded that they saw the policy version describing it. Each shop has a cap on calls, and a server switch turns it off without a release. Residual: text on the page can try to steer the model, but the click guard bounds the outcome. Accepted by the founder on 8 November 2026.

How the cap is counted. A private ledger links the existing shop's identifier to each part of that shop and keeps the number of attempts and their reserved maximum cost by month. It holds no page text or model answer. Its rows are deleted with the shop, its group or the shopper's account; shopping run records otherwise remain as described in section 8. Reservations are deliberately conservative, including when a request times out.

Tidying a typed item (added 10 October 2026)

Written before any of it is built. Typing an item today either matches an existing one exactly or makes a new one, a comma list becomes one item, and nothing sorts an item by aisle. The change asks three narrow questions of a judgment service; our own code finds the candidates and does every count, split and write.

What is sent, and to whom. TypeSafe's Jev, in the United States, is the additional processor the assistant's fast commands already use, and the same rules apply to it here: it is sent only what a question needs, with the group's member and baby names replaced first by the existing pattern, and it is never sent a group's records, a conversation or anything it could look up.

So an item's words reach a processor they did not reach before, and we say so plainly. A shopping item can say what somebody needs — a pharmacy line, an infant formula, a food somebody has to avoid — and a member's own words are what a list is made of. Two things bound it. What goes is one typed item and the handful of candidates it is being compared with, never a list, a group, a history or a record. And the same service already receives a typed request to add an item through the assistant, which is the route this change makes unnecessary for somebody who is simply typing on the list: it is a second door to the same processor rather than a new processor.

Who never uses it. A group set to Device-only, the shared display, and a child's account get the behaviour our code gives on its own — an exact match or a new item, no split, and "Other" for an aisle. Nothing they type goes anywhere. The judgment is never needed for a write to work: when it is unavailable, that same code-only behaviour is what happens, and nothing about it is shown as an error.

What the member sees. An answer of "the same" adds the item to the one already there and offers Undo. "Related" asks the member — a new item, or added to that one. An uncertain split is put to them before anything is created. An aisle is set when the answer is reasonably clear — a starting threshold of 0.6, to be set from an evaluation set before it is used anywhere — and is "Other" otherwise, because a wrong aisle costs a member nothing but a glance. Nothing is written on a judgment the member cannot see and undo, and no threshold here is a promise about how often the answer is right.

The remembered aisle. An aisle chosen for an item name is remembered for that group, so the second "milk" lands in the same aisle without anybody being asked again. It is a group record holding a member's words, so it carries the same sealing as the item it came from: the name is held sealed under the group's key, the phone opens the group's own small set of them and matches on the phone, and nothing finds a row by the words inside it — the rule that stops a sealed row being looked up by its title. It names no member and no time of day beyond when it was last used, so it is not a record of who shops for what. Keeping it on one phone instead was the alternative; it would have meant every member answering the same question, which is most of what the change is for. (C4)

What is narrower than this was written for, as built on 12 October 2026. Three things, each recorded here because the assessment above describes a design and these are what the built thing does instead. None of them widens anything, and two of them are deliberate decisions that have to be settled before the tidying is switched on rather than loose ends to tidy up later.

  1. The remembered aisle is not built. There is no record of an aisle chosen for an item name, so every typed item is asked about again. The alternative available without a database change was to read the aisles already sitting on the group's own items, and that was deliberately not done: it is a different arrangement with different properties — an item carries who added it, so a memory derived from items could become the record of who buys what that condition C4 exists to prevent — and C4 says that a remembered aisle built another way needs this assessment revised before the change is released. The paragraph above therefore describes something that does not yet exist, and the cost of its absence is one more question to the judgment service per typed item, not a difference a member would see.
  2. The notice does not yet name a typed shopping item. The two gates condition C5 asks for are in place — the member is on a client that has declared it can show the notice, and their acknowledgement has been read from their own record — but the notice those gates check is the one written for typed assistant requests and forwarded email, and typing on a list is neither. The tidying is therefore switched off everywhere, by a setting that is unset, and it answers every request with the behaviour our own code gives. Switching it on needs the notice first, which is what C5 says. Written on 15 October 2026: the privacy policy of that date names a typed shopping item, the route's minimum notice version moved to it, and the setting is now declared off in our infrastructure configuration until it is deliberately turned on.
  3. A group that is excluded, and a group whose judgment is unavailable, get no split at all — not a split on commas without the rest of the tidying. One item, an exact match or a new item, and "Other" for the aisle, which is what typing on a list does today. A split nobody checked would turn one thing somebody wanted into two things they did not, and that is a change to make deliberately rather than as a side effect of the judgment service being down.

How an item records the catalogue entry it came from, as built on 12 October 2026. The assessment above says that where a shopping item came from is recorded only where it names something of ours, and that the identifiers stay readable while the words are sealed. That is now a column of its own on the item, holding the shared catalogue's own identifier for the thing — a short text label such as pantry:salt. It is written in the two places where somebody chose the item from the catalogue rather than typing it: tapping a staple they have run out of, and asking the assistant to add something the catalogue already lists. Two items on a list carrying the same identifier are the same item, so the second one is merged into the first by our own code, with nothing sent anywhere and nothing asked of anybody.

This records nothing new about a household, and that is the point of using an identifier. The same label was already stored, readable, beside the sealed words of the row this item replaced, and it is also already stored beside the household's record of what it has run out of. The catalogue it names is the shared one every group reads, so the label names a published entry of ours rather than anything a household wrote: the words a member typed are still sealed, and no word of theirs goes into this column. Nothing new is sent to any other service, kept for longer, or made visible to anybody who could not already see the item.

What it deliberately does not record. Not the catalogue's own name for the thing — that is words, and words stay sealed. Not a meal plan's ingredients, because the catalogue gives an ingredient no identifier of its own and a plan's identifier alone would treat every ingredient of a week as the same item. Nothing about who tapped it, or when, beyond what the item row already records. It is also not used to decide whether a shop's prices may be recorded: that still rests on the separate marker the assessment already describes, and this column changes neither its rule nor its reach.

What a merge does to the price recording. An item merged into another is an item whose words have changed, so the provenance marker no longer matches the row's title and the item stops being eligible for a price record. That is the conservative direction, and it is reached by the rule that was already there rather than by a new one.

Where this may be used at all. Item words go to the judgment service only where the assistant may already act for that group and that member: the group's privacy level allows our server assistant, the member's own narrower ceiling and age and consent gates pass, they are on a client that has declared it can show the updated notice, and their acknowledgement of that notice has been read. A member or a group who has not reached that point gets the code-only behaviour rather than a silent new recipient. (C5)

What is recorded about the call. Each call is counted in the existing records of what the assistant costs — its model, counts, timing and outcome, not the words. Typing on a list is not an assistant request, so it writes nothing to the optional improvement record a member can turn on for the assistant, and nothing to a shop's own 14-day record; an item added by asking the assistant follows the assistant's existing tracing rules unchanged.

Coles (added 3 November 2026, written before the code)

Status: Assessed before the code (draft, 2026-11-03); founder approval pending. Nothing in this subsection exists yet. It describes what the Coles changes must be built to, and the conditions below (CL1 to CL19) are what keep its statements true. No Coles page is opened by any version of the app until this assessment is approved and the conditions it assigns to each change are met. The changes that add no Coles flow and no new data (the retailer seam, the per-retailer switch and the database widening) may be built first.

What is added. Coles joins Woolworths as a second supermarket in Shopping. A member who starts a shop chooses Coles on the start sheet, signs in on Coles' own page inside the app, and the phone then finds each item's Coles product number by searching coles.com.au as the member would, chooses a product with the same chain of models as for Woolworths (section 3, “Choosing a product”), and adds the chosen products to the member's own Coles trolley with one Coles link that carries product numbers and quantities (Coles calls it an “ext-cart” link; Coles has not published it). Then “Open the Coles app” hands over: the trolley is the account's, so it is already there. The member reviews and pays in Coles. GroupApp never orders, pays or reaches checkout.

What is not added. No new processor: as with Woolworths, the phone talks to Coles directly under the member's own account, so Coles is the member's own retailer and not our processor, and our servers never talk to Coles. The models see what they already see for Woolworths: the item's words, the amount on the list in the fixed form described under 'Choosing a product', the budget/standard/premium setting, up to 24 product cards and, where our catalogue found them, the search term. No Coles address, cookie, credential or raw trolley reading reaches a model, our server, a log or a trace. The store name and mode reach our server in the group-visible status (CL13); no store is sent to a model. Public product cards reach the existing decision service and models, with no product numbers sent to Jev. The optional trace still records only this run's own basket changes, never its pre-existing trolley quantities or unrelated lines (CL4). Children, a shared display and any account under 16 never shop; a member aged 16 or 17 needs the young-member AI choice turned on; a person starts every run; nothing reaches checkout or payment. All of that is unchanged from Woolworths and is restated as a condition (CL15), not assumed.

Data that is new, and where it sits.

What Where Leaves the phone?
Coles' sign-in session (its cookies) in the app's embedded browser The member's phone only. A session is a credential even though no password is kept (section 2). Ended by Disconnect, signing out of GroupApp, or another member taking the retailer browser No, except to Coles
The member's Coles email, password and text-message code Typed by the member into Coles' own page. GroupApp fills nothing and keeps nothing: there is no “remember my Coles email” and no “save my password”, as with Woolworths after the Full visit update (CL1) Only to Coles, by the member
The member's whole Coles trolley, as the page shows it Read on the phone by the page script. Only this run's chosen products (number and quantity) and, for the warning, a count and a dollar total of the other lines come out of the script (CL4). Those values stay on the phone: never sent to our server, a model, a price record or the optional trace No
The member's Coles store, or saved delivery address Held by Coles against the account, and so shown in the member's Coles app at once. GroupApp reads it on the phone each run; the model never sees it Only the store name and mode reach our server in the group's status (CL13); no address leaves the phone
The Coles link Product numbers, quantities and the fixed word groupapp; nothing else (CL5). Sent only to Coles, from the phone, inside the member's own signed-in session Only to Coles
retailer = 'coles' in shopping_runs, retailer_price_observations and shopping_match_decisions Our database. No new column and no new kind of value: the retailer becomes a second allowed value (CL12) Yes, as for Woolworths
Saved product choices and remembered Coles numbers The member's phone only, as for Woolworths, kept per retailer. A Coles number is remembered only for an item that came from our own meal-plan catalogue (CL14) No

Signing in. The member types their Coles email, password and the six-digit code Coles texts them, on Coles' page. This follows Coles' own customer agreement, which says an account holder must not give their account details to another business: GroupApp never sees the password, and neither retailer has an app-managed saved sign-in. The phone's keyboard may offer the code from Messages on its own; that is the phone's feature. The page script only reports which of three states the page is in: signed out, signed in, or challenged. It never creates an account, changes a password, accepts terms or enters checkout. Coles may text a code at every sign-in, so the sheet says so before Start.

Coles' bot check. Coles protects its site with Imperva. A page can arrive as an interruption page (“Pardon Our Interruption”) and, rarely, with a picture puzzle from hCaptcha. The phone recognises that by the page's shape (no page data, an Imperva frame or an hCaptcha frame), reloads once after a few seconds, and if it is still there hands the page to the member (“Coles wants to check this is you. Tap to retry”). A second challenge in one shop ends the shop and keeps what is already in the trolley. GroupApp never solves a puzzle, never scripts the hCaptcha frame and never retries on a timer. The phone reports each challenge to our server as a code with the app release and platform, as it does for a Woolworths page that has changed, and nothing about the member, the group or the page goes with it (CL10). Our checks allow hCaptcha only as a frame inside a Coles page, never as a page of its own.

Location. Coles' site asks for the phone's location on each full page load. The app denies it every time without asking the member (CL9), because nothing here needs it.

The member's store and address are the account's, not the run's. A Coles store or delivery address is stored against the Coles account, so changing it in a shop changes it in the member's Coles app, and the reverse. The run therefore reads it from the page at the start of every shop rather than trusting a saved copy. For Click and Collect it shows the current store and, if the member wants another, types a suburb into Coles' own dialog and reads back the stores (only those Coles names “Coles …”), telling them first: “This changes your store in the Coles app too.” For delivery it reads the member's saved addresses and lets them choose one. GroupApp never types a new address into Coles (founder, 1 November 2026): if none suits, it says “Add the address in your Coles app, then come back” (CL8). Reading the saved addresses is the same kind of read as Woolworths' store picker (section 3): bounded counts and lengths, shown to that member only, never sent anywhere.

Reading the trolley, and the rule that bounds it (CL4). Coles' link can only add; it cannot lower or remove. Before the first fill the phone therefore opens the trolley and reads what is already in it, as it already reads Woolworths' cart for the baseline. That read touches things the member put there themselves, which can be sensitive: medicine, pregnancy tests, infant formula, alcohol. The rule is that the page script returns only the lines whose product numbers are in this run's chosen products, plus a count and a dollar total of all the other lines. Nothing else leaves the script: no name, number or price of any other line. The count and total are used once, for the warning “Your Coles trolley already has 7 items. GroupApp adds to them; it doesn't replace them,” and then dropped. A test proves the shape of the script's output. If the trolley is not empty the member chooses Add on top (the default, and what Woolworths already does) or I'll empty it first (which opens the Coles app and re-reads when they return). Products go in as batches of about ten and at the end of each part, each followed by a trolley read; a line is confirmed only at its baseline plus this run's quantity. A link is never resent blind: if an attempt's outcome is unknown, the phone reads the trolley and sends only the shortfall. A line above its target, or a product missing after a fill, goes to the member as a question, never to an automatic retry (CL6, CL7).

Disconnect (founder's decision, 3 November 2026). Disconnect Coles clears Coles' website data, the Coles run state and the saved Coles choices on the phone, and leaves Woolworths signed in, on both iOS and Android; Disconnect Woolworths likewise leaves Coles signed in (CL18). Today's Android behaviour does not meet this: the app cannot list one site's cookies, so it clears every embedded-browser cookie (section 3, above). The founder did not accept that for Coles, so the fix is a condition, and Coles cannot open to members until it is met. It needs native code, so it rides the next native build. Approaches for the engineering change to choose from, none decided here: a separate Android browser profile or data directory per retailer (the multi-profile API in androidx.webkit, where the phone's browser component supports it); or clearing only each retailer's own cookie domains. Whichever is chosen must be shown to leave the other retailer's session intact on a real Android phone and on iOS.

Coles' third parties. Coles' site loads services of its own on every page: Google Analytics, FullStory (which records the page a visitor sees), The Trade Desk and others. Inside the app those services see the member's Coles session as they would in a browser, including the trolley our shop fills. They are Coles' processors, not ours, and GroupApp can neither switch them off nor see what they keep. The proposed policy wording must say so once approved by the founder; the current policy has not been extended to Coles. CL19 covers the sheet.

The group's view of a Coles shop. The status shows the retailer, the store label (“Coles Brunswick, click and collect”) and the mode, as for Woolworths: never an address, and for delivery only that it is delivery (CL13). The daily brief's two fixed sentences name “Coles” in place of “Woolworths” and nothing else. A Coles shop and a Woolworths shop in the same group are separate runs; the database already allows one active shop per group and retailer.

Arrange Coles pickup / delivery. The ordinary group task, offered on the way into a Coles shop, with the same rules as the Woolworths one: assigned to the member shopping or another adult member with their own account, never a profile, the wall or a member under 18, never an account under 16, and words that never say an order exists (CL16).

De-identified rows. retailer = 'coles' changes nothing about what those two tables hold or may hold (section 2): the same columns, the same rule that only an item marked as ours is ever recorded, and no group, member, store, shop, task, address or typed word (CL12). Coles' product names are Coles' catalogue words, and some say what somebody needs, in rows that name no person. De-identified is still not anonymous (section 3).

Saved choices and remembered product numbers. Saved choices stay on the member's phone and are kept per retailer, so a Woolworths number is never used on Coles. A Coles number is remembered only for an item that came from our own meal-plan catalogue, never for a word a member typed (founder, 1 November 2026). A remembered number is used only if this run's live search finds it again, available; otherwise the item goes through normal matching. There is no household memory shared between members: that would be a readable record of what a household buys, and it needs its own assessment (as the remembered aisle does, C4) (CL14).

Page scripts ship only in the app. The scripts that run in a signed-in Coles page are part of the app bundle and reach phones through the app's own update channel. There is no channel that serves script text from our servers to be run in a Coles page: that would be a new way to run code inside a signed-in session, and nothing here needs it. The per-retailer switch (below) turns a retailer or the link off, and nothing more (CL3, CL11).

The switch. The phone reads a small per-retailer setting from our server before every shop and again before each fill: whether the retailer is on, whether the link is on and its address template, the batch size, the most challenges a shop allows, and the oldest app release allowed. It carries no script and no member data. If the phone cannot read it, Coles is treated as off; Woolworths keeps working as it does today. With the link off, Coles shopping is paused, and the review screen still lists the chosen products for the member to add in the Coles app themselves.

Conditions Coles must meet (CL1 to CL19)

Each is testable and assigned to a change in the numbered Coles delivery sequence. “The seam” means change 2; “the switch” change 3; “the database change” change 4; “session and store” change 5; “search” change 6; “fill” change 7; and “setup” change 8. “Every Coles change” means changes 5–9 and 11. Change 9 supplies catalogue aliases and eval fixtures and must preserve CL14 and CL17. “The rehearsal” is change 10, on a real iPhone, and must pass before changes 6 and 7 are accepted. The native change in CL18 is assigned to change 11 alongside native hand-off; Disconnect isolation is mandatory before Coles opens to members, even though the hand-off enhancement is optional. If delivered separately, the Disconnect change must explicitly carry CL18 and the same native-release gate.

# Condition How it is checked Met by
CL1 GroupApp saves, fills and types no Coles credential or code. The Coles session script reports only signed out, signed in or challenged. No Coles email or password is written to storage; no “save my password” or “remember my email” for Coles A test over the Coles sign-in scripts finds no command that fills a credential or code field; a storage test finds no Coles key beside the Woolworths ones Session and store; setup
CL2 A Coles page may be the top page only on www.coles.com.au and auth.colesgroupprofile.com.au; hCaptcha loads only as a frame; checkout, order confirmation, 3-D Secure and any payment host are blocked A table test of the navigation check over allowed, blocked and framed addresses Session and store
CL3 Page scripts come from the app bundle only. No Coles page script is fetched from a server, and the switch's reply has no field that can carry script A test that every script handed to the browser is built from bundled constants; a schema test on the switch's reply The switch; every Coles change
CL4 The trolley-read script returns exactly: this run's chosen lines (number, quantity), a count of other lines and their dollar total. Nothing about another line leaves the script, and the count and total never reach a request to our server, a model request, a price or decision record, or a trace A test feeds a trolley with unrelated lines and asserts the output's exact keys and that no unrelated name, number or price appears; the request, record and trace builders do not accept the values Fill
CL5 The Coles link has exactly two parameters: cid=groupapp and product numbers with quantities (<digits>_<quantity>, separated by commas). No group, member, run or plan identifier can be put into it. The address template from the switch must be a coles.com.au address and is checked before use A test builds the link from fixtures and asserts the exact parameter set; a template pointing elsewhere is refused Fill; the switch
CL6 The link only adds. After an unknown outcome the phone reads the trolley and sends only the shortfall; a line at or above target is never resent; a missing or over-target line becomes a question A test of the fill step over an interrupted batch asserts what is sent Fill
CL7 A non-empty trolley is warned about before anything is added, with the count, the dollar total and any of this run's products already in it; the default is Add on top A test of the warning's inputs and copy Fill; setup
CL8 GroupApp never types into Coles' address field. The delivery path can only choose among saved addresses; with none suitable it shows the “Add the address in your Coles app” message. A store change is announced as changing the Coles app too A test that the Coles command list holds no text-entry command for the delivery address; a copy test Session and store; setup
CL9 The Coles page is never granted the phone's location A test of the browser's permission handler for Coles addresses Session and store
CL10 A challenge is recognised by shape, reloaded once, then handed to the member; a second in one shop ends it. GroupApp never solves or scripts the puzzle. The report to our server holds only a code, the app release and the platform Fixture pages for each shape; a test of the report's exact fields Session and store; search
CL11 The switch fails closed for Coles (unreadable means off) and is read before each shop and each fill; an app release below the minimum cannot start a Coles shop. Coles is declared off in our infrastructure configuration until the founder turns it on, and each request carries the notice floor in CL19 Tests with an unreachable, off and low-version switch; the configuration check The switch; setup
CL12 coles becomes an allowed retailer in the four database checks and nothing else changes: no new column in either de-identified table, the same marker rule, and the retailer value is a closed list A database test of the allowed values and of both tables' column lists Database change
CL13 The group's label for a Coles shop is a store name and a mode. For delivery it holds no suburb, street or address A test of the label builder given a delivery address; the table has no address column Session and store; setup
CL14 Saved choices are keyed by retailer. A Coles number is saved only for a catalogue item (one carrying our marker) and is used only if the live search shows it again and available. Disconnect Coles clears Coles choices and leaves Woolworths'. No server-side or shared memory of numbers Storage-key and item-source tests, with a typed item and a stale number Search; setup
CL15 Every eligibility rule applies to Coles as to Woolworths: personal account, 16 or over, young-member AI for 16 and 17, never a child's or shared display's account, started by a person, nothing reaches checkout or payment The existing eligibility and checkout-block tests run for both retailers The seam; setup
CL16 “Arrange Coles pickup / delivery” follows the Woolworths task's rules (adult, own account, never under 18 or a profile, words that name no order) The existing task tests run for both retailers Setup
CL17 The product decision request gains only the retailer's name. No Coles address, cookie, credential, raw trolley reading or raw page text is in any model request, log, trace or crash report, except as “When the shop's own reading fails” above allows for a transient model request. Public product cards and this run's own basket changes retain the existing decision, record and optional-trace rules; Jev still receives no product numbers. Only the store name and mode reach the group-status service (CL13); a page shown to the model can include a store name as “When the shop's own reading fails” above allows A schema snapshot of the request; the trace and log schemas are checked for those fields The seam; search; fill
CL18 Disconnecting one retailer leaves the other signed in, on iOS and on Android, and clears the disconnected retailer's website data, run state and saved choices. Coles is not opened to any member until this is met, and it needs the next native build A test of the clearing call per retailer; a check on a real Android phone and an iPhone that, signed in to both, Disconnect Coles leaves Woolworths signed in and the reverse Setup; a native change
CL19 Before a Coles shop starts, the sheet says Coles' site uses analytics and session recording of its own, that Coles may text a code, that the store or address is the account's, and that GroupApp adds to the trolley and does not replace it. The Coles choice is offered only on a phone whose bundled notice is the new version and which the member has acknowledged; the server asks for the same floor A copy test; a test of the start-sheet gate and of the server's floor Setup; the switch

CL18 and the rehearsal are conditions on release: Coles is not opened to any member until CL18 is met. The rehearsal: the search and fill changes merge only after a 40-item shop on a real iPhone in a dev build’s WKWebView, with the founder's own Coles account, shows at most one interruption cleared by one reload or tap, every line reading back at its baseline plus this run's quantity (with an empty trolley and with three items already in it, and after backgrounding the app mid-shop), and the hand-off opening the Coles app on the same trolley. It records how long a session lasts and what Coles' link does with an unavailable or over-limit product. Coles is not opened beyond the founder's household until it has passed.

Residuals we accept with Coles (3 November 2026; written before the code).

  1. Coles may suspend the member's account. Coles' customer agreement lets it suspend an account where it acts reasonably in its legitimate interests, and says nothing about automated tools. The member's own visible shop, started by them, at a human pace, on their own phone, is personal use; the risk is theirs, not ours, and we state it. Controls: the switch, a person starts every run, nothing reaches checkout, no credential is held by us, and no challenge is automated.
  2. Coles has not been asked. The link is unpublished and could change or stop without notice; the switch turns it off without a new app release, and the fallback is the member adding the chosen products themselves. Coles' website terms also forbid “framing” its website; the page the member sees is their own session on their own phone and is republished to nobody.
  3. Coles' third parties see the session, trolley included (above). We cannot reduce this without blocking parts of Coles' page, which we will not do.
  4. The trolley read touches the whole trolley on the phone. The script sees every line the page shows, and the rule in CL4 is what keeps the rest from going anywhere. That is a conventional control (code and a test), not a structural one.
  5. Coles' session cookies sit on the phone (a credential, as in section 2), ending at Disconnect, sign-out or another member's use of the retailer browser.
  6. Android sign-ins are not yet separate. Until CL18 is met, Disconnect on Android clears every embedded-browser cookie. That is why Coles stays closed to members until it is met.
  7. The store and trolley are the account's. A change in a shop appears in the member's Coles app and on their other devices, and anything the member or a household member added to that trolley is there. The member is told before the store changes and before anything is added.
  8. An interruption can stop a shop. It leaves what was already added and offers “Add the products chosen so far”.

Review again before: a Coles address, store or trolley line (beyond CL4's output) is sent anywhere; a Coles credential or code is saved or filled; a script is served to a Coles page from a server; remembered numbers are shared between members or kept on a server; GroupApp creates a Coles address or reaches checkout or payment; a third retailer is added; or Coles asks us to stop.

Proposed policy wording

The privacy-policy and automated-decisions wording for Coles is drafted in a private HQ note, kept privately, and awaits the founder's approval. It is built as the next privacy-policy version (v3.17) before the Coles choice is switched on and not before the code it describes exists, so a phone shows the notice before any Coles page can run (CL19). The automated-decisions page and its in-app copy change in the same version. No published text has been changed.

4. Choice and access

Every group has Shopping's lists. Preparing a basket is open to eligible members of any group: eligibility is checked through the signed-in member's database session on every model request, and a group name or client boolean cannot grant it. Until 6 October 2026 a protected, operator-managed grant limited this to one invited group. Starting a run is an explicit choice after the member sees that GroupApp will send selected items and bounded product options to AI, which may process outside Australia, search Woolworths using the chosen store or address, and stop before payment. Connection and automation can be declined while ordinary shopping lists remain useful. Manual product overrides remain available. An existing young-member AI consent is also required for a member aged 16 or 17; members under 16 cannot run the browser or model.

Children retain only the shared list access the group's existing per-group policies permit, which the move carries across unchanged. A guardian's retailer credentials are never made available through that list. Private run state holds no retailer password; the removal and its historical-account limitation are described under “Removing saved sign-in on this phone”.

What is chosen, and what is not, with the 7 October 2026 changes

What is chosen, and what is not, with the 10 October 2026 changes

5. Risks and controls

Risk Control Limit
Somebody who is not eligible prepares a basket Active-membership, personal-account, age, consent and privacy-setting checks on the server for every model request, repeated on the phone before a run; shared displays cannot start one A compromised member device remains a risk
A login secret reaches the model or a group member Local transient fields; strict product-card request schema; private browser The app handles the secret briefly and the retailer receives it
A model chooses the wrong food or quantity Observed-product allowlist, deterministic quantity checks, uncertain matches pause, user reviews in retailer app Product matching is probabilistic; dietary suitability and actual stock still need review
A page or item instructs the model to ignore boundaries Untrusted text fencing; model cannot return executable code, arbitrary URLs or checkout commands Prompt fencing alone cannot guarantee correct semantic matching
An existing basket is overwritten or additions are repeated Read quantity before a change, retain confirmed progress, stop on uncertain outcomes Retailer state can change concurrently; ambiguous changes need review
The assistant places an order Closed browser command set excludes checkout and payment; external app handover stops the run Retailer pages may change and must be tested
A person thinks a partial basket is complete Per-item confirmation and an explicit needs-attention state An OS-terminated task may only report its interruption on return
Background activity drains the battery User-started bounded run, cancel and expiry handling, no recurring polling outside a run Device measurements remain outstanding
A legacy saved Woolworths password remains on a phone The new app has no credential reader or writer. Known accounts’ keys are deleted without reading values, with persistent retry after partial failure SecureStore cannot enumerate orphaned historical-account keys; deletion may also wait on keychain access. The app does not claim every old copy is gone
Shopping state leaks after switching groups or accounts Explicit group/member storage keys, execution cancellation, eligibility recheck Members can still voluntarily show their phone to somebody else
A member's shopping becomes visible to their group in a way they did not expect (7 October 2026) The status holds no item word; only the member running a shop writes their own row, except that another adult can mark a left shop cancelled, which reveals nothing new; and the group already sees the lists being shopped A member who wants to shop without the group knowing cannot use this. A member who leaves a shop past 30 minutes (running or waiting) or 6 hours (ready) may find it cleared
A home address reaches the group through the status or the brief Only Woolworths' own store name and mode are written; a delivery choice writes the mode alone; there is no column for an address The address still goes to Woolworths through its own page, as before
A price or decision row is traced back to the group that produced it No group, member, store, shop, task or time of day in either table, and no read permission for any member De-identified is not anonymous: our database plus knowledge of who cooked what that day could associate a row with a group
A member's own words end up in a table nothing will ever delete The ingredient word always comes from our catalogue or pantry list; an item a member wrote carries no marker and is never priced; neither table has a column for a typed word Our catalogue's words still say what somebody was cooking; the rows say nothing about who
The provenance marker stores item words where the item's own sealing does not reach The marker's two word fields are sealed with the item's other words Conventional and test-pinned: a future writer that lists an item's fields by hand could drop it, which is how this class of fault has happened before
A deleted account leaves its shopping behind A status row goes with the group and with the member who ran it Price and decision rows are beyond an erasure's reach by design, because nothing in them points at anybody
A child is asked to place a supermarket order The pickup task is not offered to an account under 16, and its words ask for a review and an order in Woolworths' app rather than implying one exists An adult can still hand their own phone to a child
Somebody reads "Open Woolworths cart" as "GroupApp has ordered" The label names the cart; the screen says to review and order in Woolworths; the closed browser command set excludes checkout and payment Opening the retailer's app at that page is still unverified on a phone
Two members shop into the same cart at once One active shop per group and retailer, refused by the database as well as the screen; a cleared shop's phone stops adding as soon as it reads its row, and the database refuses any change to a cancelled or finished shop A phone that has lost its network keeps adding to its own cart until it can read its row, and a phone on a version from before 20 October 2026 does not check; the 30-minute wait is what makes either unlikely while a shop is really going
A shop is cleared by somebody who should not, or while it is still going (20 October 2026) One database function: an adult person in the group with their age on record and two-step sign-in; the server's clock against the row's last change, rechecked with the row locked; it can only mark an active shop cancelled, and it gives the same answer for a shop that doesn't exist and one the caller may not clear A shop that is working refreshes its last change as it finishes a step, at most every 10 minutes, and not while it waits. So a shop waiting 30 minutes on its member, a phone the system has paused, or a phone without a network still looks left. What is in the cart stays there
The group accumulates a record of who shopped and when Rows hold no item word and go with the group and with the member Nothing removes a finished shop on a timer; we have not built a window, so we do not state one
A group's shopping words are read while they are moved into the new tables (10 October 2026) The move copies ciphertext and wrapped keys as they are stored, inside one database change; no key is unwrapped and nothing is opened Written before the code: the property has to hold in the change as it is written, and a copy that read or re-sealed anything would break it
A write lands in rows that have stopped being read, or two shapes are both written Copy and freeze in one transaction; a database rule refusing every client write to a moved row or a new item-under-a-task insert, from every version; our own assistant server's writer stays off until the release A phone on an old version has its writes refused rather than redirected, so somebody has to update before adding to a list
An erasure is blocked by a frozen row, or outlived by one (C1) The refusal covers a client's write, not a deletion arriving with the group or the member being deleted; the frozen rows are deleted weeks later For those weeks the same sealed words exist in two places, and an item deleted in that window has a frozen twin until the clean-up
A member's typed item is lost by the move or by a refused write (C2) A refused write fails visibly and keeps the words; a queued item create from before the upgrade is replayed onto its list, or shown as failed with the words kept A member on an old version cannot add to a list until they update
A basket prepared before the move stops resolving after it Every item keeps its identifier, so a saved shop finishes and ticks the same items A shop saved before the move is still subject to everything else in section 8
A member's item words reach an additional processor overseas (10 October 2026) One typed item and the few candidates it is compared with, with names replaced; no list, group, conversation or record; only where the assistant may already act; never from Device-only, the shared display or a child's account; code-only behaviour otherwise A food can say what somebody needs, and a typed phrase can identify a person despite name replacement; TypeSafe processes it in the United States, and no retention term is assumed
A judgment merges two different things, or splits one thing in two A merge only on a clear answer, with Undo; a "related" answer asks the member; an uncertain split is put to them before anything is created; every write is our code's A wrong merge past the Undo has to be retyped, and a member who does not read the line may not notice
The remembered aisle becomes a readable record of what a group buys (C4) The name is sealed under the group's key like the item it came from, matched on the phone, never looked up by its words; no member column Conventional until it is built: the sealing and the matching are code, and this assessment is the condition rather than the proof
A typed item's words try to instruct the judgment service It only picks among candidates our code supplied, or answers yes or no; it cannot name a tool, a person, a write or a place to send anything A wrong answer is still possible, which is what the bands and the Undo are for

6. Structural and conventional controls

Database grants and membership policies protect enrolment. Existing sealing protects shared words. Server access and privacy gates, fixed global Vertex model transport, strict request validation, observed-product validation, native task lifetimes and the closed command set constrain execution. Domain validation, transient credential handling and cleanup are application controls backed by tests, not guarantees against a compromised phone. No claim of perfect security or zero liability is made.

The 7 October 2026 changes, property by property. Structural means the database, a constraint or a missing permission can prove it, and it survives a careless change. Conventional means code, copy or a test holds it up. A test-pinned property is not proof, but it fails loudly.

Property Structural or conventional
Only active members of a group can read its shopping status Structural — a per-group row policy, the same kind the group's tasks use
Only the member running a shop can write or change its row, except that another eligible adult can mark a left shop cancelled Structural — a policy that checks the writer against the row, and one function (clear_abandoned_shopping_run) that checks the caller, their age, two-step sign-in and how long the row has been left, with the row locked, and writes only the status and the finish time
A cancelled or finished shop is never reopened, and a failed one can only become finished Structural — a trigger refuses the change, whoever writes it
Who cleared a shop is not recorded Structural — there is no column for it
One active shop per group and retailer Structural — enforced in the database, with the screen's refusal in front of it
A status row goes when the group goes, and when the member who ran it deletes their account Structural — and checked in the built table (7 October 2026): both references delete the row with their parent, so neither blocks an erasure
No member and no group can read the price or decision tables Structural — no permission is granted to a signed-in reader at all. Reading is the structural half; see the next row for who writes
Only our shopping service writes to the price or decision tables Conventional (revised 7 October 2026; the writers are now built as described here). The first draft of this assessment said our assistant server writes them with a privileged key of its own. It cannot: that server is deliberately not given the key that would bypass every household's row permissions, because keeping that key away from it is what makes a breach of our cloud provider survivable. So each table has one narrow database function that performs the write, which the app reaches through that server, and which re-checks that the caller is a real person, not a shared display, not an account under 16, signed in with two steps, and a member of some group. The function is callable by any signed-in member, so "only our service writes these" is practice, not proof. Nothing in the privacy argument rests on it: what keeps these rows harmless is that eligibility is decided from the structural marker (the next rows) and that the tables have no column for a group, a member, a store, a shop, a task or a time of day to put anything in. The worst a direct caller achieves is junk in our own price history
Neither table can hold a group, member, store, shop or task Structural — the columns do not exist
Neither table can hold a time of day Structural — the column is a calendar date
Neither table can hold a word a member typed Structural in shape (no such column) and conventional in practice (the ingredient word is chosen by code that reads the marker)
A repeated attempt does not duplicate a row Structural — a unique index over the row's own key
Only an item whose marker names something of ours is priced, or described in a decision row Conventional, test-pinned — decided on the phone and checked again where it is written
The marker's words are sealed with the item's other words Conventional, test-pinned — the sealing map is code, and a round-trip test is what notices if it is dropped
Match decisions are sent only when the member has turned the switch on Conventional — the switch is on the phone, and our server cannot verify what it cannot read
The matching choice is asked again after twelve months Conventional — the phone's own record of when it was given
The pickup task never implies that an order or a booking exists Conventional — its words, pinned by a test
No address reaches the status or the brief Structural for the table (no column); conventional for the brief sentence, which code composes. A page shown to the model can include an address as “When the shop's own reading fails” allows
The brief's sentences are fixed and ask no model Conventional, test-pinned — they are composed from the row
A pointer at one of our pantry items is readable, and names the item Structural and deliberate — our pantry list identifies items by name, so the pointer is a word, in the marker and in both de-identified tables. It is not sealed, because identifiers are not. Nothing is disclosed that a group's own pantry record does not already hold in plain text beside the task it created

The 10 October 2026 changes, property by property. None of them is built. Each is a property the change has to have for this assessment to be true of it, and the five labelled conditions are the ones a reader should hold us to.

Property Structural or conventional
An item's words stay sealed under the group's key, by the same key scheme as the task row they come from Structural — the same keys, and a move that copies ciphertext rather than words
Only active members of a group can read its lists and items Structural — a per-group row policy, the kind the group's tasks already use
Quantity, unit, aisle and the tick are readable state Structural and deliberate — they are fields, and the line the rest of the app draws puts a small structured fact in the clear and a payload under a key
Our servers cannot fill those fields from a member's words (C3) Structural — they cannot read them
The move opens nothing Structural — it copies stored bytes inside one database change, and no key leaves a phone
No gap between the copy and the freeze Structural — one transaction
No version of the app can write a moved row, or a new item-under-a-task row Structural — a database rule, in front of a version gate that fails open
A deletion arriving with the group or the member still removes a frozen row (C1) Structural, and the thing to check in the change as written — the same check the group's view of a shop needed, for the same reason
A refused write keeps the member's words and says what happened (C2) Conventional, test-pinned — the words are on the phone and the message is code's
A queued item create is replayed or shown as failed, never dropped Conventional, test-pinned — the queue's existing rule, extended to a new table
An item keeps its identifier through the move Structural — the copy states it, and a saved basket depends on it
Ticking an item writes no row to the task-completion history Structural — the tick is a field on the item
Item words reach the judgment service only where the assistant may already act (C5) Conventional — server-side gates and a client capability, as the fast-command route has
Device-only, the shared display and a child's account send nothing Conventional, test-pinned at the entry points — the same exclusions the fast-command route states
The judgment is never needed for a write to work Structural in effect — the write path does not call it, and its absence is the code-only behaviour
The remembered aisle's name is sealed, and matched on the phone (C4) Conventional — the sealing map and the matching are code, and a round-trip test is what notices if either is dropped
The remembered aisle names no member Structural, if the column does not exist — which is what this assessment requires

7. Children

Shopping notes are not readable or writable by anyone under 18 or by managed accounts, in the database as well as the app. A note an adult writes may mention a child: names on the group’s lists are replaced, and the modal asks them not to write names or health details.

See 'Who' in 'Looking further for a product: more searches and one product page' above.

Families benefit from less duplicated shopping work. Existing shared shopping words can already mention a child, so the tool must preserve their protection. The retailer runner excludes accounts under 16 and requires the existing personal AI opt-in for ages 16–17. Shared displays cannot operate it. Clearing another member's left shop (20 October 2026) is for adults only: nobody under 18 or whose age is not on record can clear one, and nor can a shared display or a profile. An adult who clears a 16- or 17-year-old's left shop learns nothing about it they could not already see. It never uses a child's profile to infer purchasing needs. This does not change our wider assessment of the service's child-related obligations.

The 7 October 2026 changes (added 7 October 2026). What a child in the group gains is small and real: they can see that the shopping is being done, and by whom, instead of asking. What it costs them is also small — one more fact about an adult's day is on their screen, and nothing new about the child is stored. The price and decision records hold nothing about any member, child or adult, and they are written from our own catalogue's word for a food rather than from what somebody typed, so a dietary or health need written into an item does not travel with them. A child is not offered the shop itself (under 16), the matching switch, or the pickup task, because that task asks the person holding it to place a supermarket order.

The safer design we considered and did not choose was hiding a running shop from child accounts. We did not, because who is doing the shopping is an ordinary fact of a household, the lists themselves are already open to the children in the group, and hiding only the status would make the app treat shopping as adult business without protecting anything. Where the interests diverge — a parent who would rather the children not see what time the shopping happens, against a child who can see who is doing a job that affects them — we let the child see it, because the alternative hides a fact they can get by asking and buys no privacy.

The 10 October 2026 changes (added 10 October 2026). Nothing a child types goes to the judgment service: a child's account gets the code-only behaviour, as it does for every other use of that service. A child can add, see and tick items as they can now, and the move changes nothing about which lists a child can read — including on a phone that has not updated, where the lists stay readable and a write is refused with a message rather than failing quietly. The remembered aisle holds no member, so it is not a record of a child's shopping, and an item's new fields hold a quantity, a unit and an aisle rather than anything about a person. What a child loses is the tidying itself: their "milk, eggs and bread" stays one item until somebody splits it, and their items are sorted into "Other". We prefer that to sending a child's words to another country, and the gap is a tidier list rather than anything they need.

An amount written on a shared list, including by a child, reaches a model only as a number and a unit from our fixed list; other words in the unit field stay on the phone.

8. Accepted residuals and the general-release review

The requested pilot accepts that an undocumented retailer UI may stop working, authentication can require a person, the operating system may interrupt a run, and a native retailer app may require a separate login. We retain a useful list and show incomplete work honestly. A filled basket is not an order and never automatically completes a shopping task. These are the bounded trade-offs authorised for the pilot on 4 October 2026.

General-release review, 6 October 2026. The pilot's results were reviewed before Shopping was opened to every group. A two-item run on a test phone and a thirteen-item run on a member's iPhone each prepared and verified a basket; the iPhone run kept working with the phone locked. The store picker read Woolworths' own store choices. Signing in needed the person each time a code was sent, which the run handles by pausing. Not yet observed: Woolworths' app opening at the prepared basket and showing the same items, a run on Android, and battery use. Where the app does not open, GroupApp asks the member to open Woolworths themselves; a basket that does not appear there is still not an order. GroupApp accepted these on 6 October 2026 and will revisit them as results arrive. No new data, recipient or retention comes with general release: each member still chooses to start a run, and the same eligibility, AI and privacy checks apply.

Residuals we accept with cart runs (7 October 2026; re-read against the built code)

  1. Observed prices are recorded without a way to decline. Every eligible item in every shop contributes a row, and no setting turns it off. We accept this because a row names no person, no group and no store, and because offering a switch would tell members the rows are about them. What we are accepting in plain terms: a member cannot stop GroupApp recording, from their shop, what a food in our own catalogue cost at a Woolworths store on a day. If that is not acceptable, the change is a second switch beside the matching one and this assessment should be read again.
  2. De-identified is not anonymous. Stated in section 3 and accepted: with our database and outside knowledge of who cooked what, a row could be associated with a group, and would then disclose a supermarket price.
  3. A shop is visible to the member's whole group. There is no private shop.
  4. A finished shop's row stays while the group exists. Nothing sweeps it. We are not building a window in this change, and so no copy will claim one.
  5. Two of the properties that keep members' words out of the de-identified tables are code, not the database. Which items qualify, and which word becomes the ingredient, are decided by code with tests behind it. The tables' missing columns are the structural half; this is the other half. Added 7 October 2026: so is who writes them. Section 6 explains why the write is a narrow database function any signed-in member could call rather than a privileged key only our server holds, and accepts the consequence — someone could add rows that are not a real observation. That is a cost to the usefulness of our own price analysis, not a disclosure about anyone, and it was accepted in preference to giving our assistant server a key that reads every household. A second write path that would restore the stronger property is named in the engineering notes and not built: a small function inside our database provider's own environment, which holds such a key already. It would need its own release process, and it cannot be run or tested on a developer's machine, which is why it was not chosen now.
  6. The matching switch cannot be read, checked or expired by our servers. A phone that was never updated would keep sending under old words. The 14-day record it feeds can be deleted on request; the de-identified rows cannot, because nothing identifies them.
  7. Opening Woolworths' app at the cart is still unverified on a phone. Unchanged from 6 October
    1. The clearer label does not change what has been seen working.
  8. What was asked for was aggregated data; what this describes is rows. The decision this revision assesses asked for de-identified data for longer-term matching analysis, in the language of aggregates. What is assessed, and what the table holds, is one de-identified row per product decision, kept with no end date — broader than the word aggregate suggests, because an aggregate can be computed from rows and not the other way round. We accept it in those terms rather than letting the narrower word stand over the wider design. Counting the rows up and keeping only the totals would be the narrower build, and it remains available.

Residuals we accept with clearing a left shop (20 October 2026; written before the code)

  1. The last change is not a heartbeat. A member who leaves a sign-in pause or a ready basket past the wait can have their shop cleared. Nothing in their cart is lost; they start again.
  2. A phone that cannot see the clear keeps going. A phone without a network, or on a version from before this change, keeps adding to its own cart until it reads its row, and the household may buy something twice. It cannot reopen the shop.
  3. Not naming who cleared it is not anonymity. GroupApp keeps no record of who cleared a shop, but in a small group the member can often tell, and our hosting provider's request logs hold the call as they hold every request.
  4. Finish after a clear marks off items that a newer shop may also be buying. Those items really are in the first member's cart.

A claim elsewhere that this revision found wrong, in three places. A model choosing which product goes into a member's cart is an automated decision with a dietary consequence, and it has been made since Shopping was released. Three documents still count the automated decisions without it, and all three are corrected in the same change that ships the work assessed here:

Each of those sentences is held in place by a test that pins the old number, so none of them fails on its own: the count has to be moved deliberately, in all three, with their tests. The correction is not deferred on the ground that this revision did not create the omission.

Residuals we accept with Shopping's own items and the tidying (10 October 2026; written before the code)

  1. For some weeks after the release, a group's shopping words exist in two places. The frozen rows are a real copy, sealed under the same key and readable by nobody new, and they are deleted once the raised minimum version has been in place long enough. An item deleted in that window still has a frozen twin until then. We accept it because deleting the old rows in the same change would leave no way back if the move were wrong, and because a group's or a member's own deletion still takes its frozen rows with it (C1). After the clean-up, a list's title can still exist in both places where a member made that list one of their plans or linked it to a goal, until the group is deleted; we accept that rather than delete somebody's plan without asking.
  2. A member on a phone that has not updated cannot add to a list. Their lists stay readable and their writes fail visibly, with a message asking them to update. We accept a visible refusal in preference to two shapes both being written, which is the failure that loses a list rather than delaying one.
  3. A typed item's words go to an additional processor in the United States, and there is no switch for that alone. What governs it is the group's privacy level and the member's existing assistant and overseas-processing choices, with the notice naming TypeSafe acknowledged on a client that can show it. In plain terms: a member who wants the assistant but not their shopping words in that service has only those levers. If that is not acceptable, the change is a switch of its own and this assessment should be read again.
  4. Names are replaced, and a phrase can still identify somebody. "Ada's birthday cake" is a shopping item. We accept it on the same terms as every other use of that service, and because what is sent is one item and a few candidates rather than a list.
  5. Quantity, unit and aisle become readable, and some of them used to sit inside sealed words. A number, a unit and one of the app's own aisles beside a sealed name say how much of something, not what it is. We accept the trade because sorting a list by aisle and adding a quantity up are what the fields are for, and because the words themselves do not move.
  6. A wrong merge or split is the member's to notice. A merge offers Undo while it is on screen; past that, the item has to be typed again. Nothing is deleted — a merge adds to an item rather than removing one — but somebody who wanted two separate things has to ask for them twice.
  7. Everything in this revision is a condition rather than a description. None of it is built. C1 to C5 are the five properties the change has to have for the paragraphs above to be true, and each is a thing to check in the change as written rather than something already checked.

Findings for the build.

What differed, found while building (12 October 2026)

Recorded because this document was written before the code, and an assessment that is not corrected by what building taught is worth less than no assessment.

9. Retention and review

Shared list records retain the existing task retention and erasure rules, and keep them in Shopping's own tables after the change assessed on 10 October 2026 (below). Local preferences can be changed or removed in Woolworths settings; Disconnect removes the saved store, product preference, saved product choices, run progress and retailer state on this phone. Without the separate sharing choice below, product-selection requests are processed transiently and only token and spend accounting metadata is retained. Full browser pages are never recorded. Review this assessment before shopping notes are offered to anyone under 18, read by an additional check, or shown outside the group; or before adding another retailer, cloud-hosted browsing, broader page interpretation, server credential storage, purchase actions, or background scheduling without a user start.

How long the three new records are kept (added 7 October 2026)

Read this assessment again before: either de-identified table gains a column; a price is shown to a member; anything a member typed becomes eligible for either table; the group's view of a shop gains an item word or keeps a longer history; the matching choice moves off the phone or becomes something our servers can read; a third retailer is added (the second, Coles, was assessed on 3 November 2026 in section 3); or a pickup task can be given to an account under 16.

What the 10 October 2026 changes keep, and for how long (added 10 October 2026)

Read this assessment again, too, before: the judgment service is asked anything about an item beyond the three questions in section 3; a list, a group, a conversation or a stored record is added to what it receives; the tidying is offered to a child's account, the shared display or a Device-only group; the remembered aisle stops being matched on the phone, or gains a member; a frozen row is kept past the clean-up for any reason other than a member's plan or goal, or the rows are deleted before the raised minimum version has done its work; or an item's own words become readable to our servers for any reason.

Optional shopping improvement record

(6 November 2026, assessed before the shadow/control diagnostic change, requested by HQ.) On missing Add controls, record a bounded outline of the first product container: at most twelve element paths/custom tags, shadow-root presence and clickable tag/role/type/disabled state. Operational logs accept only fixed first-word action labels (Add, List/Lists, Save, Remove, Checkout, Quantity, or Other); unknown names become Other, never product/account words. Only a consented trace can contain control names clipped to 24 characters, scrubbed against the roster; without a readable roster it gets the fixed labels too. No input values, URLs, addresses, other text or identifiers are collected. Existing consent, recipients, retention and erasure apply. Residual: a clipped product-control label may contain product words already covered by this optional record; the outline may omit later controls or closed shadow roots.

(6 November 2026, assessed before the add-confirmation hotfix; requested by HQ.) A consented add_result event records only the acted-on control's fixed tag (button/link/input/other), role (button/spinbutton/none/other), action (Add/Quantity/Other), and observed quantity or unknown. It carries no raw name, product or page text. An add_unconfirmed operational drift code reports a mutation without a quantity read-back. Existing recipients, consent, retention and erasure apply; a local quantity change still requires the existing saved-cart verification.

At each start, a separate “Help us improve shopping” checkbox starts off. It sits on the start sheet, directly above its explanation. Since 10 October 2026 that explanation is in two layers: what is shared, with LangSmith (LangChain, a US company), for 14 days, that item words can include dietary or health details, and that it is for this run only (shown); where the record is stored, that names from the group are replaced, and that login details, codes, addresses and payment details are excluded open one tap away under it, before Start (one tap). The facts did not change, so the wording version moved to 1.3 and a start from an app still on 1.2 is accepted and recorded as 1.2. The same sheet is shown to everyone who can shop, including 16- and 17-year-olds who have turned on AI features themselves; we accept the shorter explanation for them too, under our principle of being useful first, with informed opt-in, because the checkbox still starts off for every run and the line above it names the recipient, the country of its operator and the sensitive content. Checking it shares this run only; it does not turn on assistant-chat tracing or remember a choice for the next shop. This is an explicit sending, not a standing twelve-month permission. Starting with the checkbox checked records the wording version and time with the run. There is no consent inferred from membership of the invited group. The member can turn sharing off during the run; steps already sent keep the retention below.

When chosen, one record follows the run: search queries and product cards, extra searches the model asked for and the fixed product facts read from a product page, model instructions and answers (including the active shopping notes, with names replaced, their count, and the numbers of those the model said it used), checked choices and quantities, saved choices, basket changes and verification, background/foreground transitions, pauses, cancellation, interruption and the attempted retailer-app handover. Model steps include their model, region, token counts, duration and outcome. Login fields, passwords, codes, cookies, addresses, payment details, full pages and raw browser messages are excluded by the event schemas. The group's member and baby names are replaced before text is sent; if the names cannot be read, the record contains only status labels and counts. Names outside that list and sensitive details someone writes into an item can remain.

(6 November 2026, assessed before implementation; requested by HQ.) The first entry describes the shop's fixed goal: retailer, fulfilment, product tier, item count, basket filling without checkout, time limits, the enabled/minimum-version settings used and whether they came from a served reply, defaults or a timeout, wake-lock request/activation state, app and platform. The run identifier remains only in root metadata under TR1. Search diagnostics count result tiles and recognised enabled/disabled Add controls, quantity inputs and missing controls, including the fallback reader's product containers. They record only fixed signed-in/unknown labels, whether a store is recognised and matches the run’s setup (never its name), fulfilment mode and explicitly recognised slot state. Endings record selected, review, unavailable and confirmed-added counts, fill-step outcomes and the existing stop code. These closed labels and bounded counts also reach operational logs without the optional trace choice, for failure diagnosis; those lines contain no run, trace, group, member, product or device identifier, query, item words, store name, address or raw page text. Schemas reject additional fields. Existing trace access, recipients, consent wording, retention and erasure are unchanged. Residual: aggregate page labels can be wrong when the retailer changes its controls; unknown is retained rather than inferred as signed out or out of stock.

(12 November 2026, shopping incident; bounded diagnostics permitted by Security.) On a positively identified Woolworths search page, the existing operational search diagnostic may also report whether the bounded scan hit a limit, whether a main element, a loading marker or an explicit zero marker was seen, and the product-link count as 0, 1–9 or 10+. These are closed booleans and an enum; no page text, URLs, attributes, search terms or identifiers are sent. The diagnostic is suppressed on member-held pages, detected sensitive fields or blocking dialogs, and when the safety scan cannot complete. Open shadow roots are included; closed roots remain uninspectable. Existing operational recipients and retention apply.

The record is sent to LangSmith, operated by LangChain, a United States company, and stored in its Australian region in the same project as existing consented assistant traces. It has the same 14-day base retention, no retention-extending feedback or datasets, and the same pseudonymous account tag for deletion on request. Support access from abroad remains unverified. The member's choice can expose shared item words about other people, including dietary or health needs; GroupApp accepts that residual with this disclosure and an off-by-default choice, for the pilot on 4 October 2026 and for general release on 6 October 2026.

A signed, expiring reference binds the trace to this member and group across requests and server instances. Each upload checks current access and Device-only settings. No tracing key is held by the phone. Failed trace uploads do not stop shopping; the phone reports that the record may be incomplete. An operating-system kill or loss of network can leave a partial trace. The trace begins marked incomplete and only reports a completed basket after the phone confirms it. Credential entry before Start and actions after entering the retailer app are outside the shopping record. Sign-in progress during a run contributes only the broad milestones described above.

(30 October 2026) The record's top entry also carries the run's own random identifier from this phone, so that an operator investigating a shop the group's view shows can find its record. Nothing new is stored in our database: the group's view of a shop still says nothing about whether the run was shared, and the identifier goes nowhere else (no log, no de-identified table). It is kept and deleted with the record, on the same 14 days and the same deletion on request. An operator who uses it records the access in the operator access register.

10. Assessment coverage

Purpose, necessity and data flows are addressed in sections 1–3; choice in section 4; harms and controls in sections 5–6; children's interests in section 7; residuals and review in sections 8–9. This assessment relies on the existing published group-content and assistant assessments for the unchanged task and chat storage paths. The 10 October 2026 revision relies on our assessment of the assistant's fast commands for the judgment service itself — what it is, where it runs, what it is told and what it is not — and assesses here only what Shopping sends it, where that is allowed, and what Shopping does with the answer.

The assistant can show a Shopping opener containing only a closed tool identifier. The server offers it only to a member's own phone that can show it, never a shared display; the opener holds no shopping words, credentials or arbitrary URL. Starting the native task still requires the member's action on the phone.

11. Sources

Screen awake during an active shop (3 November 2026)

Assessed before implementation: an active shop keeps the screen on while its shopping screen is in front. Leaving that screen, putting GroupApp in the background, a pause, ending the run or closing the screen releases that request. Before Start, the member sees an estimate based on about 18 seconds per product need. A stopped shop shows how many list items have not been confirmed in the cart, including parts still to come, beside the existing way to start again.

These changes use the progress already held on the phone. They add no collection, storage, recipients, model input or permissions, and do not change eligibility, background execution or the ten-minute run limit. The existing assessment applies. The visible screen may show shopping information for longer and use more battery; the member chooses Start after being told the screen will stay on. Release on loss of focus and on every terminal run state is enforced by lifecycle cleanup and tested. Device auto-lock behaviour still needs a phone check.

10 November 2026: pantry review and shared-list lifecycle

Approved before implementation on 10 November 2026. Meal-plan groceries and pantry-check ingredients are shown together in separate sections. Pantry ingredients start selected when the plan is chosen. Members check what is at home and can leave individual ingredients out of that shop without changing the shared list. A matching open item on a standing list is included with a chosen plan to avoid a second purchase; compatible plan amounts add together and use the larger of that total and the existing standing-list requirement. Incompatible amounts require a member to leave one source out or edit the amounts. Only the remaining selection enters the existing retailer and AI flow, under the same eligibility, notes, notices and consent safeguards. No new processor receives data.

A shared Remove offers 15 seconds to undo. The original row remains during that window; restoring it clears the removal rather than creating a copy. Other members see the removal too. A running shop prevents removal, and interrupted apps do not restart or extend the server's deadline. After the deadline the row cannot be restored and is deleted by scheduled cleanup. This qualifies the earlier statement that explicit deletion is immediate.

Ticked items remain recoverable for 14 days. Putting one back clears its completion; a later tick starts a new server-timed window. Old completion timestamps were supplied by phones, so existing ticked rows receive a fresh 14 days when this change is installed. Unknown dates never cause bulk deletion. Expired items cannot be restored, even if physical deletion must wait for an active shop. New runs also keep their source item identifiers and bounded row-revision timestamps on our server with their status, so a start can refuse a selection removed or edited on another phone. These references contain no item words and are deleted with the run, including on group or operator account erasure. Older run snapshots are held only on phones, so cleanup conservatively retains a group's item rows while any shop is active. Group and account erasure retain their existing behavior; these windows do not delay erasure.

Standing lists, including Pantry, remain available when empty. Empty completed meal-plan lists are archived only after their plan ends and no shop is active. Their identities and task links remain, with a restore action. Reusable custom lists are archived only by an explicit member action. Archiving is shared and is not deletion. Residual risk: an abandoned shop can delay physical item deletion until it is cleared; offline phones can show an older cached view until they reconnect, but cannot restore an expired row on the server.

Implementation clarification after the single founder-requested review (11 November 2026): existing authenticated DELETE policies are retained. Authenticated direct item DELETE requests the same 15-second shared removal window; repeated calls cannot shorten or extend it. Direct list DELETE archives instead of cascading through recovery. Group/account erasure cascades remain immediate, including during an active shop. An older app checks only the delete error, so its request still completes, but it cannot display the new Undo control and may briefly redisplay pending rows on reload until cleanup. Another member on the updated app can undo the shared removal. The current app carries each selected item’s list kind into setup and refuses unknown provenance; these checks add no personal data or recipient.

CI compatibility clarification (11 November 2026): actual service SQL roles and direct database-owner sessions retain physical cleanup outside active shops. The trigger does not infer this authority from a JWT role claim or from its SECURITY DEFINER owner. The existing service-only delete_group_now removes the group root; account erasure uses the group-deletion workflow and Auth administration. Root erasure cascades remain immediate, including during active shops. Tests exercise owner/service group erasure, authenticated definer contexts and account attribution cleanup. This restores existing privileged erasure behavior without changing retention choices, member disclosure, consent, recipients or the two private guide keys.