← All privacy impact assessments
PIA: Targeted notices — task notices and event detail confirmations
Approved by the founder, 26 October 2026. §12, "Creator notices and prompts", and the rows marked "Creator notices" in §§2, 3.2, 6 and 9. Tasks Option B adds "Can't do this": a member who can't do a task gives it back, asks someone else, or says it doesn't need doing, and only the task's creator is told, once, quietly, in the Tasks tab's notice strip — no push and no chat post. The creator may also be asked, on their own phone, about a task nobody has taken for three days or one more than fourteen days overdue. Nothing is reassigned or closed by itself, nothing counts per person, and child accounts get no timed prompts. It collects one optional short note and who skipped a task.
Planned, 10 October 2026: three notifications nobody asked for. The app is being changed so that it may interrupt a member to tell them a person did something that concerns them — somebody else gave them a task, a person joined one of their groups, or their request to join or connect was approved. Until now the app only notified a member about something they had asked for themselves, or because another member chose to send them a notice. None of it is built. It collects nothing new: each notification is set off by a fact the app already holds — an assignment, a membership, an approved request — and no AI model is asked whether to send one.
The task one is a change of trigger, not of transport. Telling the people a task was assigned to already works exactly as this document describes — one notice per task, one row per recipient, the group's name and the one approved generic line on the lock screen, identifiers only, nothing that carries the task's title. What changes is who decides: today the member creating the task ticks a box (off unless they tick it); from this change, assigning a task to somebody is itself enough. A task created by the member's own assistant, and a task that already needs their approval and already notifies them, are both excluded.
What bounds it. Every such notification names a group and a person and nothing else, and in a Phones-only group it names nobody. A member gets at most three notifications a day that they did not ask for, counting these, the first-week suggestions and the existing daily catch-up together; notifications about the same thing within ten minutes are combined into one; and reminders a member set, or a daily brief they chose, do not count towards it. Each kind has its own switch, and the switch can be found again. Child accounts, the shared display's account and profiles are excluded and keep the old rule — nothing interrupts them unless somebody asked for it.
The new risk, stated plainly. Today a member can only be interrupted about a task if the person creating it chose to interrupt them; afterwards, being given a task is enough. That is a real loss of quiet, and it is the trade this change makes deliberately: a member who joined and typed a list of jobs into the app heard nothing from it again. The protections offered against it are the three-a-day limit, the ten-minute combining, the per-kind switch, and the rule that the notification still never carries what the task says. What is not offered, and is accepted as residual: a member cannot stop another member assigning them a task, and cannot see who chose to notify them, because nothing records that choice any more.
Status: Draft, written before the code, and since revised as one half was built. Two features share one audience design and are assessed together: telling chosen members about a new task, and asking chosen members to confirm an event's details.
Build status, 18 September 2026: the event detail confirmation half and its reusable recipient-only delivery primitive are built. The database enforces one response per chosen recipient and current event version: the first confirm or owner-private "not now" wins, an identical repeat is a no-op, a conflicting repeat and a stale version are refused atomically, and different recipients answer independently. The shared chat card is one-per-request but is marked so the ordinary whole-group message trigger sends no push. The dedicated push carries only the request/group identifiers, the group name and the fixed generic lock-screen line; the event title, question and recipient list are never copied into it. Delivery is claimed on a stable request/recipient/device identity and uses the existing push-delivery receipt ledger. Save, request, card and delivery report structured outcomes, and a retry repeats only unfinished work.
Both halves are now built (task notices added later on 18 September 2026). A task notice has its own three tables — the notice, its recipients, and each recipient's own seen row — with the database enforcing that a recipient is an active member of the task's group, that there is one notice per task and one row per recipient, that a recipient's seen state is readable by that recipient alone, and that every row cascades from the task, the group and the member. Delivery rides the same identifier-only transport: one claim per notice, recipient, device and the moment that recipient was named, so a re-send that adds somebody else never pages the people already told, and a retry never pages a device twice. The sender is told that the notice was recorded and whether the notification went — never who has seen it. A child account may be named (§7), and because a child's account has no assistant surface, their notices appear as a strip on their own task list instead. The words a recipient reads are composed on their device from the task and the roster; no model is involved. Written: 18 September 2026 · Last revised: 26 October 2026 (§12: creator notices and prompts, Tasks Option B PR2, approved by the founder) · 21 October 2026 (§11: muting one group's notifications, built) · 10 October 2026 (the amendment at the top: three planned notifications nobody asked for, and the limit on them) · 18 September 2026 (task notices built) Nothing here is legal advice. Children's Code citations are to the exposure draft; section numbers may move on registration (due 10 December 2026).
1. Purpose and scope
Today, when a member creates a task or wants an event's details checked, the app offers two blunt instruments: assign the task and hope the person notices, or announce it to the whole group's chat. This design adds a third, narrower one — calling a specific member's attention to a specific record, without interrupting everybody else:
- A task notice. After creating a task, or from its details, a member can send a short factual notice to chosen members: "Sarah added a task for you." It lands in the recipient's own attention area, links the real task, and clears when they have seen it. It is attributed to the actual sender — the app never writes a pretend conversation in which the recipient appears to have asked their own assistant to create it.
- An event detail confirmation. From an event's editor, a member can ask chosen members to confirm the details as they stand — time, place, attendees, or a short typed question. This is a different job from the existing "ask the group to fill this in" card, which is about missing fields: a confirmation records that a named member looked at a named version of the event and said "yes, that's right". If the event changes afterwards, the record shows the confirmation covered the older version. Confirming details is not an RSVP and is not permission to create or change anything.
- One save-then-ask operation with honest outcomes. Saving an event, recording a request, placing its shared card and delivering the recipient-only notice can fail independently. The design requires each to report its own result — "Event moved. Couldn't send the request — Retry" — and a retry must repeat only unfinished work, never re-save the event, re-record the request, duplicate the card or page a device twice.
The principle the whole design hangs on: targeting routes attention; it never creates a private channel. Choosing recipients decides whose attention surfaces raise a card and whose phone is interrupted. It does not hide the underlying task, event, request or question from the rest of the group, and the app says so wherever recipients are chosen.
In scope: the recipient model (who can be named, what a recipient row holds, who can read
it), the notice and confirmation records, delivery and push behaviour, and what each party is
ever shown about the others. Out of scope, covered elsewhere: the forwarded-email cards
that will reuse this audience model (assessed in the group inbox
assessment — which also records the one exception this design does not
otherwise have: since 22 September 2026, a group's owner or admin reads and resolves an
INBOX_PROPOSAL card whatever its audience, from the Mail Sifter item screen rather than the
Assistant tab, so a card nobody named opens is not stranded until the 30-day sweep — a database
read/update rule scoped to that one card TYPE, and no other targeted-notice surface gains an
equivalent); invitations that cross a group boundary (assessed in the
cross-group events assessment — nothing in this design crosses one);
and task reminders a member schedules for themselves, which already ship. Those reminders are
promises a member made to themselves, which is the first of the four reasons the app may
interrupt anybody at all (the rule, and the three others added on 10 October 2026, are in the
amendment at the top of this document).
2. Data involved
| Kind | Whose | Children's? | Sensitive? | Free text? |
|---|---|---|---|---|
| A notice record: sender, the task or event it points at, the chosen recipients, when it was sent | the sender's act, about a record the group already holds | possibly — a recipient or a task's subject can be a child | no new content — it carries identifiers; the words shown are composed on the reading device from rows the reader can already see | no |
| A per-recipient seen state | the recipient's own | possibly | no | no |
| A detail-confirmation request: the event, which details are being checked (a closed list), the version being checked, and an optional short typed question | the requester's | possibly — the event can be about a child | possibly — the question is typed by a person | yes — the question, capped short |
| A confirmation: who confirmed, when, and which version of the event they were looking at | the confirmer's | possibly | no | no |
| A dismissal: that one chosen recipient set aside that version of the request, and when | the recipient's own, readable only by them | possibly | no | no |
| Creator notices (§12): that a member gave a task back or thinks it doesn't need doing — who, which task, who is told (the creator; an owner once the creator has left), when, and an optional note | the member's own act, about a task the group already holds | possibly — a member or the task's subject can be a child | possibly — the note is typed by a person | yes — the note, capped at 200 characters by the column |
| Creator notices (§12): an open "ask someone else": who asked whom to take which task, when, and an optional note | the asker's | possibly | possibly | yes — the note, capped the same way |
| Creator notices (§12): that a task was skipped — when, and by whom (two columns on the task) | the creator's act (an admin's once the creator has left) | possibly | no | no |
| Creator notices (§12): a member set aside a notice, an ask or one of the two prompts — which, and when | the member's own, readable only by them | possibly | no | no |
Not collected, deliberately, and each absence is load-bearing:
- No sender-visible decline, and no reason field for one. Event confirmation keeps one owner-private dismissal so the same current-version card stays settled on that recipient's devices and an identical response is a no-op. Nobody else — the sender included — may read it, and it carries no explanation. An ignored request leaves no response row at all. The unbuilt task-notice half must not infer from this that a sender-visible refusal is allowed.
- No sender-visible seen state. The seen state exists so the recipient's own badge clears and so retries cannot duplicate a notice. The sender is never shown whether, when, or which recipients have seen anything — see §5, because this is the single most consequential absence in the design.
- No free text on any recipient-scoped row. The one typed field (the confirmation question) lives on a record the whole group can read (§3). Nothing a member types travels in a channel only some of the group can read.
- No counts. Nothing tallies notices sent, notices ignored, confirmations given, or response times, per member or otherwise.
3. Flows and locations
| Data | Device | Supabase (Sydney, ap-southeast-2) | Model provider |
|---|---|---|---|
| Notice and confirmation records, recipient rows, seen state | written and read by members' devices | stored as plain structured state, unsealed, the same as every other shared action card — see §3.1 | never — no step of either feature involves a model |
| The typed confirmation question | typed on the requester's device | stored in plain text on the group-readable request row — §3.1 says why, and what bounds it | never |
| The push notification | shown on the recipient's lock screen | dispatched through the existing push pipeline, with its delivery ledger | never |
- No model, anywhere. A factual notice needs no model to compose it, and the design forbids one: the sentence a recipient reads is assembled on their own device from the sender's name and the task's own row. This also means nothing in this feature is affected by a group's choice about where model processing happens — there is none.
- Amended 29 October 2026 (message text and titles in notifications). From the release that carries privacy policy v3.15, a task notice ("added a task for you") may say "New task for you: <the task's title>", the title read from the task's own row when the notification goes, for a recipient 16 or over with "Show message text in notifications" on, on a phone that reported it can show it, in a group whose chat isn't encrypted and isn't Device-only, while our switch is on; a sealed title stays generic. Event confirmations, key-access notices, connection requests and photo reports are unchanged. The bullet below describes everything else, and every task notice until that release.
- The push never carries the record title, at any privacy level. Event confirmation sends the group name plus one approved generic line and identifier-only navigation data. The dispatcher does not query the event title or question, so Device-only and sealed titles have no exceptional branch that can fail open. Full words appear only inside the app, rendered from rows the device is already allowed to read. F17 must keep the same title-free contract.
- What reaches a log: delivery outcomes and error codes, never the notice's subject or the question's text — the same log discipline the push pipeline already keeps.
- Nothing crosses a group boundary. Recipients can only be active members of the same group as the task or event. A mirrored event that lives in another group's calendar keeps its own group's control; a request raised about it is raised inside the group that raised it.
- Residency, stated precisely rather than as a blanket claim. The household's own rows and content stay in our Sydney database, and there is no model call anywhere in this feature, so the residency question that governs our assistant surfaces does not arise for the notice, the recipients, the seen state, the confirmation or the typed question. What does leave the country is the push, and it does so on the path every notification this app already sends takes: our dispatch service hands a message to the platform push services — Apple's and Google's, reached through the delivery service the app uses — which are operated overseas and route through their own infrastructure. What crosses on that path is the push itself: the device address, the group's name, and the short line the recipient sees on the lock screen — which carries no task or event title at any privacy level, only that something in that group needs them (§3.1). That is the same overseas exposure the app's existing reminders and message notifications carry, and this feature adds one more kind of push to it rather than a new destination. Nothing else in the feature — no recipient list, no seen state, no question — is ever sent to a push provider.
3.1 Encryption tier, and what a Device-only group gets
The typed confirmation question is the only content in this feature, and it is stored in plain text in our database. It is a small structured field on a shared card, which is the same posture every other shared action card's payload already has — the app's end-to-end sealing covers large content a member authored (photographs, chat messages, an event's notes and place) under keys that exist only on devices, and deliberately does not cover the structured state our server has to be able to act on. Saying this plainly matters more than the choice itself: an operator holding our database can read a confirmation question, and no copy anywhere may imply otherwise.
Three consequences the build must honour:
- The question is capped short by the column itself, and the screen says what it is for — a detail to check, not a message. The cap is a database constraint rather than a composer's limit (§6), which is what makes it a real bound on a plaintext field; alongside its being group-readable (§5), a member who would not write something on a card the whole group can read is unlikely to write it here.
- A Device-only group loses nothing and gains no exception. Every step is structured state plus a generic push. The dispatcher never reads a task or event title for any group, so there is no Device-only conditional whose failure could expose one.
- A sealed title is never copied into a notice. For a group whose titles are sealed on the device, the notice carries identifiers; the reading device renders the title from the row it can already open. Nothing in this feature unseals anything or stores a second, plainer copy of a title — which is the mistake to avoid, because a "denormalised for the notification" title column would quietly undo the sealing for every notified row.
3.2 Retention and deletion
Notices and confirmations are derived attention state about a record, not records in their own right, and the design's rule is that they never outlive the thing they point at:
- The task or event is deleted: its notices, recipient rows, seen state, confirmation requests and confirmations go with it, by a database cascade rather than by a sweep. A notice pointing at nothing is a card whose button cannot act, and a confirmation about a deleted event is a fact nobody can check.
- Delivery evidence follows the request and the account. The event-confirmation request's
deletion removes its targeted
push_deliveriesrows; account erasure reaches them throughuser_id. Receipt reconciliation therefore retains only the same operational token, ticket, outcome and error fields as existing pushes, never a title, question or recipient-list copy. - A recipient leaves the group, or is removed: their recipient row and seen state are removed with their membership. The sender is not told; the request shows as unanswered rather than as pending with somebody who is gone (§5).
- An account is erased: every row in this feature keys on a member through a foreign key that cascades, so a departing member's notices (sent and received), seen state and confirmations are removed by the same account-deletion path the rest of the app already uses and evidences off-provider. Nothing in this feature may store a member identifier in a way an erasure cannot reach — in particular, a notice must not keep the sender's name as text for display after the account is gone; the name is resolved from the roster at render, and a departed sender renders as a departed member.
- The group is deleted: everything goes with the group, the same as every other group-scoped table.
- No independent expiry, deliberately. We considered sweeping old notices on a timer and rejected it for two reasons. It would be a second, quieter retention rule over content whose real lifetime is its parent record's, and — the one that decides it — automatically time-limiting member-visible content is the shape the platform's age-classification analysis turns on, so adding a disappearing surface to buy tidiness is a poor trade. A notice's resolution removes it from attention; the row goes when the record does.
- Nothing here is logged. Delivery outcomes and error codes only, as §3 says, so there is no copy of a question or a recipient list in a log that an erasure cannot reach.
- Creator notices (§12). A creator notice, an ask and a dismissal cascade from the task, the group and every member they name, like everything above. A task that was skipped is kept as long as the task itself, like a completed one, and is seen in History's "Skipped" list; who skipped it is set to nobody if their account is erased. No sweep or timer removes, closes or hides any of it. The two prompts are worked out on the creator's phone and stored nowhere; only "set aside" is recorded, once per task and kind.
4. Legal basis and consents
No new consent purpose is created and none is needed. Sending a notice is the sender's own deliberate act about a record the group already shares — the same basis as assigning the task in the first place — and nothing new is collected.
Nor is any new destination introduced, which is the accurate form of the claim. One path leaves the country, and it is the existing push path disclosed in §3: the device address, the group's name and the short lock-screen line, through the platform push services every notification this app already sends passes through. Beyond that payload, no household row or content is processed outside our Sydney database, and no model is called at any point. This feature adds another kind of push to that path; it does not add a recipient of anybody's data who was not already receiving pushes for this app.
Delivery respects each recipient's existing notification settings; a recipient who has turned notifications off still gets the in-app card and no push. The consent ledger is not touched: there is no switch here, because there is no new destination or kind of processing to consent to — the overseas push path is the one the app's existing notification disclosure already covers, and nothing in this feature widens what travels on it.
5. Risks and mitigations
| Risk | Who is harmed | Mitigation | Structural or conventional? | Residual |
|---|---|---|---|---|
| The sender is shown which recipients have seen a notice — which is a read receipt, a feature this app removed for every member because showing anybody how others engaged with their material is what would change the app's legal position under the under-16 rules | every member, and the app's own standing | Seen state is readable by its own recipient alone, under a row policy that names them; no query the app ships returns another member's seen state; the standing source scan that keeps feedback features out of the chat and photo surfaces is extended over these new surfaces | Structural for the read policy; the scan is test-pinned | Acting on a notice reveals engagement inherently — a task completed is visible as a completed task. Accepted: that is the record, not a meter on the person |
| Dispatch status drifts into engagement status — "Sent ✓✓" becomes "Seen" one well-meant edit at a time | recipients | The design allows the sender exactly two statements, both about our own delivery machinery: the notice was recorded, and the push could or could not be dispatched (with Retry). Copy is pinned by test to say nothing about the person | Conventional — copy, test-pinned | A sender can still ask the recipient in person, which is the correct channel |
| A notice becomes a nag machine — repeated sends to the same person about the same record | a member, often the least powerful one in the group | Event confirmation has one request and one shared card per event; delivery has one stable claim per request, recipient and device. Retrying cannot stack a card or page the same device again. F17 still owes its own one-task/recipient uniqueness before it can reuse the transport | Structural for the built event uniqueness and delivery key; the task half remains gated | A member can still edit and deliberately re-ask about a genuinely new event version. Accepted — the current request is visible to the group |
| The same recipient confirms and dismisses concurrently, or a stale device answers after the event changed | the recipient and the group's records | One RPC locks the request/recipient pair and checks that both the request and response name the event's exact current version. The first response wins; the same repeat is a no-op; an opposite response or stale version is refused. Different recipients remain independent | Structural — transaction lock, exact-version checks and recipient FK | — |
| A confirmation is read as covering the current event after the event has changed | whoever turns up at the old time | A new stale confirmation cannot be written: the RPC refuses it. An already-recorded confirmation can become historical after a later edit, and every rendering beside the newer version says it covered the older one | Structural for the write refusal and stored version; conventional for the sentence being rendered | A member who reads only the tick and not the sentence can still be misled. Accepted, with the display rule test-pinned |
| Declining to confirm deletes the event or reads as declining to attend — the card-conflation failure this app has had before, where declining a dinner invitation deleted the dinner | the whole group | Confirmation cards get their own card identity that shares no resolution path with event proposals, invitations, or task approvals; declining removes the request from the decliner's attention and nothing else | Structural — a distinct card kind, pinned the same way the existing prefixes are | — |
| The short question becomes a private message lane inside a group whose conversations are deliberately all group-visible | members not in the exchange, and children especially | The question lives on the request record, which every active member of the group can read — recipients are who gets interrupted, not who gets to see. The recipient rows that are member-scoped carry no text at all | Structural — there is no free-text column on any recipient-scoped row | A determined pair can still exchange words by editing questions at each other. Accepted: the exchange is group-readable the whole time, which is what removes the incentive |
| The typed question holds something sensitive and sits in our database in plain text, unlike the group's photographs, chat and event notes | whoever the question is about — often a child, since events about children are what get checked | It is short by a constraint on the column itself, group-readable by design (so it is written knowing the household will read it), and never in a log; §3.1 states the posture rather than implying the sealing that covers other content covers this | Structural for the cap (a database constraint, not a composer's limit) and for there being no recipient-scoped text column; the plaintext posture is stated, not mitigated | Accepted, and it is the sharpest edge in this design. A member can type something regrettable into a field an operator could read. Sealing it would mean our server could not act on the card, and a private lane is the thing §5 refuses above |
| A notice outlives the task it points at, or survives a member's erasure as a name in a row | a departed member, whose erasure would be incomplete | Every row cascades from its parent record, group and member; the sender's name is resolved from the roster at render rather than stored as text (§3.2) | Structural for the cascades; conventional for the render-time name resolution | — |
| A departed member is named as a recipient, or departs while named | the sender, whose ask silently reaches nobody | Recipients are checked against active membership when the notice is written; a recipient who later leaves loses access with their membership, and the sender's next visit shows the request unanswered rather than pretending it is pending with someone | Structural for the membership check; conventional for the honest display | — |
| The shared chat card triggers the ordinary whole-group push, or a retry pages recipients twice | every group member, especially the least powerful recipient | Event-confirmation messages carry a request marker that makes notify_group_message return before dispatch. The dedicated transport atomically derives only active recipients from the exact current request version and claims a unique request/version/recipient/device ledger row before sending; same-version retries claim only rows explicitly recorded retryable and there is no whole-group fallback |
Structural — marker constraint, trigger arm, current-version and active-member batch claim, recipient/token validation and full unique delivery key | A process death after the provider accepted a request but before a ticket was recorded is ambiguous; the row is marked unknown and is not automatically resent |
| A sealed or Device-only title is copied into a chat row, push payload or delivery log | the household, especially a child named by the event | The card link and push data carry identifiers only. The targeted dispatcher never queries the event title or question, and the delivery ledger stores operational identifiers/outcomes only. One generic lock-screen line is used for every privacy level | Structural for the identifier-only card marker/ledger shape; source- and payload-tested for the dispatcher | The group name still appears on the lock screen, accepted in §8 |
6. Structural versus conventional
Structural and built for event confirmation — the database enforces these; the client is not the boundary:
- Recipients must be active members of the record's own group, enforced where the row is written, not where the picker is drawn.
- A per-recipient dismissal row is readable by that recipient alone; confirmations are the group-visible coordination fact.
- No recipient-scoped row has a column that could hold prose.
- One request and one marked group-readable card per event request; retries return no-op rather than duplicating either.
- A response is per chosen recipient and exact current event version. One transaction lock serialises confirm/dismiss for that recipient; an identical repeat is no-op, a conflict or stale version is refused, and another recipient answers independently.
- Direct member writes to response tables are revoked; the RPC and recipient foreign keys are the only member path.
- One delivery claim per request, exact event version, recipient and device uses a full unique key. The atomic batch claim re-checks the current event version and active sender/recipient membership, retries only rows durably marked retryable, and feeds the existing receipt ledger.
- A provider or ticket failure is reported as retryable/partial only after the matching durable ledger update succeeds. A failed ledger write can never be reported as committed or complete.
- The marked chat card returns from
notify_group_messagebefore its whole-group dispatch; the dedicated transport has no whole-group fallback. - Every row in the feature cascades from its parent record, its group and its member (§3.2), so deletion and account erasure reach all of it without a sweep to remember.
- The typed question's length cap is a constraint on the column, checked by the database whatever wrote the row, not a limit the composer applies on the way in. That is what makes "short by constraint" in §3.1 and §5 a fact rather than a convention, and it is the deliberate choice between the two: a cap that only the screen enforces is a cap a second write path silently loses.
- Writing or dispatching a request after the sender leaves, or against another group, is refused.
Structural and built for task notices — the same posture, with the differences named:
- Recipients are active members of the task's own group, checked where the row is written (a child account is allowed, §7; a pending member and a stranger are refused before any row lands).
- One notice per task, by a unique index; one row per recipient, by the primary key. A re-send adds only the people not yet named and returns "nothing new" otherwise — the sender cannot re-page somebody by sending again, because a recipient's delivery identity is the moment they were first named.
- A recipient's seen row is readable by that recipient alone; the notice and its recipient list are group-readable coordination facts. There is no way to write a seen row for anybody else, and no client may write any of the three tables directly — the two functions are the whole of the permission.
- Every row cascades from the task, the group, the recipient's membership and the member who named them; the delivery evidence is removed with the recipient row or the notice.
- Delivery is claimed only through the same service-side function pattern as event confirmations, only by somebody who named a recipient, and only while both they and the recipient are still active members.
Creator notices (§12) — structural; the database enforces these:
let_go_atandlet_go_byare set only by two functions that stamp the caller and the time; a trigger refuses every other write of them, the service role's included, and refuses reopening a skipped task by a plain update. The one exception is account erasure: once a person's account has gone,let_go_byis cleared with it; the same change from anyone while they still exist, a member or the service role, is refused.- Only the task's creator skips it, or an owner or admin once the creator has left the group; a child who created a task may skip it. Who created a task is itself kept by the database: the app, the wall and the assistant are stamped as the creator of what they add, whatever they send, and no member can change a task's creator afterwards, to themselves or to nobody. Only server jobs, our own database functions and account erasure write it otherwise.
- Not in an archived group, which stays read-only to every one of these functions; and not for a routine or tally of any vintage, a rota, or a task The Deal owns, whose closing belongs to the Routines tool and the game.
- A skipped task is closed with no completion row, so nothing that scores or counts completions sees it. The readers that leave out a closed task (the brief, Home, the allocator) leave it out too, and the reminder query refuses a skipped task explicitly, because it deliberately reads past "closed" for a repetitive task.
- "Suggest closing" writes a suggestion row, never
let_go_*. Its recipient settles it: closing is their own skip; keeping it is their own owner-only dismissal, so the person who suggested it cannot tell. - Give back, take me off and accepting an ask each change only the caller's place on the task, in one update over the row's current assignees, so anyone else's concurrent change survives.
- Creator notices and asks are group-readable; dismissals are readable by their owner alone; no client may write any of the three tables, only the functions.
- The note's 200-character cap is a constraint on the column, on group-readable rows only.
- Every row cascades from the task, the group and each member it names.
Conventional and built for task notices: the sentence a recipient reads ("Sarah added a task for you", or "Sam sent you a task" when the sender is not its creator) is composed on the device and attributed to the member who named that recipient; the sender's status line names only the notice and the notification; the source scan that keeps feedback features out of the app covers the new module, slice and both screens.
Conventional — held by copy, tests and review:
- The words a recipient reads are composed on their device from rows they can already read; nothing composes them server-side, and no model is involved. A source check pins the absence.
- The sender's two delivery statements say nothing about the person.
- The "covered an older version" sentence renders wherever a confirmation is shown beside a newer version.
- The dispatcher never queries or copies a task/event title for any group, and its fixed generic line plus identifier-only data are payload-tested.
- The feedback-feature source scan covers the new surfaces.
- The sender's name is resolved from the roster at render rather than stored as display text, which is what keeps an erasure complete (§3.2).
- The screen's description of what the question is for — a detail to check, not a message. (The cap itself is structural, above: a client that forgot to enforce it would be refused by the column.)
7. Best interests of the child
A child who is a member can be a recipient — children hold tasks, attend events, and are exactly who "the bins are yours tonight" is often for. The design's obligations to them:
- What a child gets: a notice that names a real task on their own list, on a surface their account already has. The child-safe variant of the app has no assistant conversation, so a child's notices surface on their task list and home attention area — the design must not assume an assistant surface exists for every recipient.
- What it costs them: interruption, and the low-grade pressure of being singled out. The protections are the absences in §2: nothing records that a child ignored a notice or how long they took. An owner-private dismissal is kept only on the child's account and shown to nobody else; an adult cannot open any screen that shows it. That separation is the design's answer to the summons problem — a notice can call for attention once; it cannot become a ledger of unresponsiveness.
- The safer design considered: not allowing children as recipients at all. Rejected, because the alternative in practice is worse — the whole-group announcement, which puts the same ask in front of the child and an audience.
- Whose interests won where they diverge: the child's, on visibility (their dismissal is owner-private and no engagement meter exists); the parent's, on being able to direct a task at them at all, which is ordinary parenting made legible.
No model is involved anywhere in this feature, so nothing about a child travels to one.
8. Residual risk we accept
- Acting reveals engagement. A recipient who completes the task or confirms the details is visible doing so, because the act itself is a group record. We accept this: the alternative — hiding who confirmed — would defeat the feature, and "who answered the question" is a coordination fact of the same kind as an RSVP.
- The recipient list is itself a small record of who was asked, kept with the request so the group can understand the ask. We accept it: it is the sender's own act and group-visible; confirmation is a visible coordination fact, while dismissal remains owner-private.
- Copy discipline is permanent work. Several of the properties above (delivery wording, version sentences, no engagement vocabulary) are conventions with tests, and a future change could erode them one sentence at a time. The review trigger below is the check.
- A push is a lock-screen surface, and it leaves the country. Two things accepted together, both on the same terms as every notification the app already sends (§3): the line and the group's name pass through overseas push infrastructure we do not operate, and even with titles never included, "you have something waiting in Family" on a lock screen tells a passer-by the app is in use. What this feature adds is another kind of push on that existing path, not a new destination — and the household's own rows, the recipient list, the seen state and the question never travel it.
- The typed question is plaintext at rest. §3.1 and §5. We accept it for a short, structured, group-readable field, and the honest statement — rather than a promise of sealing this feature does not have — is what the copy must reflect.
- No independent expiry. §3.2: these rows live as long as the record they point at, which for a long-lived repeating task is a long time. We accept it rather than adding a time-limited member-visible surface.
9. Review trigger
Both features are built and this document now describes them. It is re-read if any change proposes:
- any sender-visible per-recipient state — seen, delivered-to-device, response time, or any aggregate of them (this is the line between a coordination tool and a feedback feature);
- free text on a recipient-scoped row, or any recipient-scoped surface that is not readable by the whole group;
- a retention rule of this feature's own — a sweep, an expiry, a disappearing notice — or a row that stops cascading from its parent record, its group or its member (§3.2);
- a stored copy of a title, a name, or the question outside the row that owns it — a denormalised column "for the notification" undoes both the sealing (§3.1) and the erasure guarantee (§3.2);
- a count, streak, or per-member summary derived from notices or confirmations;
- recipients outside the record's own group;
- a model composing, summarising, or prioritising notices.
- Creator notices (§12): a push or a chat post for a creator notice, an ask or a prompt;
telling anyone but the creator (and the person asked, for an ask); a count, filter or summary by
who gave back or skipped (History must never filter by
let_go_by); anything that closes, reassigns or skips a task without a person's tap; a timed prompt on a child account; or the person who suggested closing, or asked, learning that it was kept or declined.
10. Checklist against exposure draft s 38(2)
| s 38(2) | Requires | Answered in |
|---|---|---|
| (a) | nature, scope, context, flow and purposes of handling children's personal information | §§1–3 |
| (b) | why the collection is strictly necessary | §2 — the records are identifiers over rows the group already holds; the one typed field is the question the feature exists to ask |
| (c) | lawful and fair collection | §4 |
| (d) | consistency with the best interests of the child | §7 |
| (e) | how we comply with the Code and the Act | §4 and §6 |
| (f) | risk of harm to children | §5, §7 |
s 38(3): this assessment preceded the build and was revised against the event implementation; it still precedes and gates F17. s 39: listed on the published register.
11. Muting one group's notifications
Built, 21 October 2026. A member can mute one group's notifications on their own account for 8 hours, for a week, or until they turn it back on. They do it from the group's own screen, just below its children, and they see and undo every mute under You → Notifications → Muted groups. Muting and unmuting need a connection. A mute made on one phone shows on the member's other phones the next time they open the app there. Every notification the app sends about that group is covered by one rule, in one place, and that rule decides which notifications a mute can never silence.
What is stored. One row per member and group: who, which group, and when the mute ends (empty means until they turn it back on). No reason, no history of earlier mutes, and nothing about any notification that was held back. The row belongs to the membership, so it can't outlive it.
So that a reminder the member set for themselves can always reach them, each task now records who last set its reminder. The database writes that, from whoever changed the reminder, whether in the app or through the assistant on their behalf, and nobody can write it directly. Like who created the task, the group can see it. If that person's account is erased, the task forgets who set its reminder. A reminder set before this change has no record of who set it, so it counts as set by somebody else until it is next changed.
Who can read it. Only that member. Other members, the group's admins and owner, and the assistant cannot read it. Whether somebody muted a group is a sign of how they engage with it, and the app never shows anybody how others engage (the ban self-assessment in this register). A member can't write the row directly either: one server function writes it, after checking that the caller is a member of the group, and works out when it ends.
When it ends. 8 hours is 8 hours of elapsed time. A week ends at the same time on the member's own clock seven days later, so a daylight-saving change in between doesn't move it by an hour. The phone's own time zone is used rather than the group's, because a mute belongs to the member and describes nothing the group shares. The end is shown on that clock too ("Muted until 6 pm"). On the phone, a muted group's feed countdown on the lock screen is removed, and it comes back when the mute is turned off or ends.
What a mute silences: chat messages, task and event notices, assignments and join requests, the daily catch-up (a muted group drops out of its count and names), reminders somebody else set, a profile's reminders sent to the adult who receives them, connection requests to the group, Mail Sifter suggestions, reported-photo notifications (the in-app list of reported photos is unaffected), and the baby feed countdown on the lock screen.
What a mute never silences:
- a reminder the member set for themselves (the last person to set a task's reminder, or the author of an event reminder);
- notices about phones and keys: a phone asking for the group's key, and a key being delivered;
- invitations to join a group, which have their own switch;
- notices that a phone was removed, that keys changed, or about who owns the group. These are shown in the app and in the group's chat, which sends no notification for them, so a mute can't reach them.
The member is told these exceptions before they choose to mute: the choices sit below them, on the same sheet. Their own notification switches, and their phone's notification settings, still apply on top. Muting changes no switch, so unmuting never turns on something they had turned off.
Notifications already on their way. Each notification is checked against the mute at the moment it is sent, including a retry of one that failed earlier. A retry held back by a mute is removed from the delivery record, as if it had never been sent. The sender's app then sees what it sees for a member whose phone can't get notifications, rather than a failure it keeps offering to retry, which would tell them somebody had muted. Nothing records that it was held back.
Children can mute their own notifications, like any member. If a notice meant for a child's guardian about the child's safety is added later, it will be an exception.
How long it is kept. The row goes with the membership: when the member leaves or is removed, when the group is deleted, or when their account is erased. A departure and a mute at the same moment can't leave a row behind. An ended mute stops working at once and is deleted within 15 minutes.
| Property | Structural or conventional |
|---|---|
| Only the member reads their mute | Structural: row-level security on the member's own rows, and no client can write the table |
| A mute can't outlive the membership | Structural: the row is keyed to the membership and deleted with it |
| A reminder the member set themselves is told apart | Structural: the database records who last set a task's reminder on every write from the app or the assistant, and overwrites any attempt to write it directly; an event reminder's author is fixed by row-level security |
until is worked out by the server, and only members can mute |
Structural: the one write function checks membership and computes it |
| Every notification kind is mutable or an exception, and an unclassified kind is an error | Structural in the database (the rule raises an error for a kind it does not know). Conventional, with a check over the source that fails the build until somebody reviews it: any new notification kind, any database statement that names the record of deliveries, any code file that sends a notification, any change to one of those files, and any notification the phone schedules itself. A name put together while the app runs would not be seen; nothing does that |
| Every sender asks before it sends | Structural for the notices whose deliveries the database claims; for the four senders that send first and record after, each decision is a tested function, and the same check fails any change to those senders until it is reviewed |
| A mute never changes a preference | Structural: the write function touches only the mute table |
Residual risk we accept.
- A sender may notice a silence. A notice to one member who muted reads, to the sender, the same as a notice to a member whose phone can't get notifications: "No new notification was needed." We accept this. Nothing tells the sender which of the two it was.
- A failed check sends. If a sender can't read the mutes, it sends the notification rather than silencing the whole group. A mute is a preference, and losing everybody's notifications to one failed read would be the worse error. If a reminder sender can't read who set a task's reminder, it treats the reminder as set by somebody else.
- The group can see who last set a task's reminder, as it can see who created the task. We accept this: it is a coordination fact about a shared task, not about how anybody engages.
Re-read this section if a change proposes showing anybody a member's mute, adding a notification kind (the register check will fail until it is classified), or muting one of the exceptions above.
12. Creator notices and prompts
Approved by the founder, 26 October 2026. Tasks Option B, PR2 (HQ security check of Option B, conditions SC1–SC12), built to this description.
What a member can do. "Can't do this", from a task's sheet, offers:
- Give it back (or Take me off this, when others share the task): the member comes off the task and nobody else moves. When that leaves nobody on it, the task's creator is told: "Sam gave back ‘Fix the gate’."
- Ask someone else: the person asked sees "Sam asked you to take ‘Fix the gate’." with Take it and Not now. The task stays the asker's until the person asked takes it. "Not now" is their own and nobody else sees it, so the asker never sees a decline.
- It doesn't need doing, for the task's creator (or an owner or admin once the creator has left): the task is closed and kept in History as "skipped". For anyone else this becomes Suggest closing it, and the creator sees "Sam thinks ‘Fix the gate’ doesn't need doing." with Close it and Keep it.
- An optional short note travels with a give-back, a suggestion or an ask. Every choice has an Undo.
Who is told, and how. Only the creator, once, in the Tasks tab's notice strip, and the person asked, for an ask. No push, no chat post, no badge count. A creator notice and an ask are group-readable, like every other task notice (§1: targeting routes attention, it never creates a private channel), and only their recipient is shown them. Setting one aside is the recipient's own row, readable by them alone.
The two prompts. Worked out on the creator's phone from facts the group already holds, never by a job on our server: "Nobody's taken ‘Fix the gate’ yet." (Ask someone / Skip / Keep it) once a task has had nobody on it for three days since it was added or last given back, and "Still needed?" (Keep / New date / Skip) once it is more than fourteen days overdue. Each comes once per task. Child accounts get neither (the 10 October amendment keeps child accounts free of interruptions nobody asked for); they do see notices a person sent them.
What is never shown or counted. No duration ("you've had this for 12 days"), no count of give-backs or skips, per person or at all, and History never filters or names who skipped a task. Nothing is reassigned, closed or skipped without a person's tap.
Children. A child account has full Tasks: a child can give back, ask someone else, skip a task they created, suggest closing one they didn't, and receive a creator notice or an ask. The protection is the same as §7's: nothing records that a child ignored or declined anything, and an adult cannot open any screen that shows it.
Encryption. Task words have been ordinary text protected by the database since 17 October 2026 (content-encryption v3), and the note follows the task: plain text on a group-readable row, capped by its column, never in a log. A member who would not write it on the task should not write it here, and the field sits on the same sheet as the task.
| Property | Structural or conventional |
|---|---|
Only the creator (or an admin once they've left) skips a task; nothing else writes let_go_* |
Structural: the two functions and a trigger; who created a task is stamped by the database and can't be changed by a member; erasure alone clears who skipped it |
| Archived groups, routines, tallies and Deal cards are refused | Structural: the functions check them |
| A skipped task never sends a reminder | Structural: the reminder query excludes it |
| A suggestion never closes a task; keeping it is invisible to its author | Structural: a separate row, settled by the recipient's own dismissal |
| Giving back or handing over changes only the caller | Structural: one update over the row's current assignees |
| Notices and asks group-readable; dismissals owner-only; no direct writes | Structural: grants and row-level security |
| The note is capped | Structural: a column constraint |
| No push, no chat post | Structural by absence: nothing in the functions reaches the delivery pipeline or the chat |
| The prompts are worked out on the phone, once per task, never for a child | Conventional, tested; the "once" is a dismissal row |
| No duration, no count, no filter by who skipped | Conventional, tested by copy and source checks |
| Tasks whose date has passed (PR2b, 26 October 2026): when a member opens the assistant, at most once a day, a card lists their own such tasks, and Today offers the same list on a tap ("Go through them"). Worked out on the phone from task dates, never written to the conversation, never sent to a model, never for a child unasked; "Keep" is the same once-only dismissal as "Still needed?" | Conventional, tested; the once-a-day mark stays on the phone |
Residual risk we accept. A member who looks at a task can see that a creator notice or an ask exists, because the rows are group-readable; that is the same coordination fact as an assignment, and the alternative is a private channel. The note is plain text, like the task it is about.
13. Sources
Primary: the Children's Online Privacy Code exposure draft, ss 10, 14(3)(b), 38, 39; the Online Safety (Age-Restricted Social Media Platforms) Rules 2025, s 4A(5)(a), read alongside the ban self-assessment in this register (which is why sender-visible seen state is refused outright rather than weighed).
In repo: lib/detailsRequests.ts (the existing household fill-in card whose machinery and
prefix discipline this design extends); lib/pendingActions.ts (badgeCount and seen
references); supabase/migrations/20260905123533_action_stacks_audience.sql and
20260905135802_close_action_stacks_insert_hole.sql (the audience column and the insert
predicate the recipient model builds on); supabase/functions/dispatch-task-reminders/reminders.ts
(lockedReminderBody, the push-title rule); components/Chat/__tests__/noFeedbackFeatures.test.ts
(the scan to extend); store/__tests__/detailsRequestPrefix.test.ts (the card-conflation pin);
our internal engineering rules on RSVPs versus proposals, on the app never deciding to
interrupt anyone, and on a declined handoff not being recorded; docs/pia/2026-09-ban-self-assessment.md
§5.3; docs/privacy_posture.md. For §11: supabase/migrations/20261021181115_group_notification_mutes.sql
(the table, the write function, the rule and the claim checks); supabase/functions/_shared/mutes.ts
(the senders that send first); agent-server/checks/genericPushes.check.ts (the register of
every notification kind and its class); __tests__/group_notification_mutes_rls.test.ts. For §12:
supabase/migrations/20261025221527_tasks_cant_do_this_let_go_and_creator_notices.sql (the
columns, the guard, the three tables and the functions); lib/taskCantDo.ts (the copy, the
choices and the two prompts); __tests__/tasks_cant_do_rls.test.ts; lib/__tests__/taskCantDo.test.ts; for the PR2b row, lib/pastDateTasks.ts and lib/__tests__/pastDateTasks.test.ts.