Automated decision-making disclosure

The Children's Online Privacy Code (exposure draft s 28) gives a child, or a person with parental responsibility, the right to request information about how their personal information is handled, and s 28(2)(g) lists "whether there is any automated decision-making, including profiling … and, if so, clear and meaningful information about the context of such decisions, including the logic involved and the consequences", answered within 30 days. This page pre-answers that request for everyone rather than waiting to be asked. Read precisely, the Code requires the answer on request; it requires a plain-language explanation of any automated decision-making the app does. This document is that explanation, written for anyone who needs the fuller, more technical version — the in-app copy at app/automated-decisions.tsx (constants/automatedDecisions.ts) is the same claim in shorter, plainer language for the person using the app. Issue #228; background in docs/privacy_posture.md §4.2.

There are three automated decisions in this app

  1. Who does a task or event. When a household adopts a meal plan or auto-allocates a batch of tasks, the AI task allocator decides who should do each item, from a list the app already built. The rest of this document is about that one, because it is the one with rules worth explaining.
  2. Whether a written review or a dish photo meets the content rules. submit-review classifies a written recipe review against a fixed list of categories before it is published; a review it rejects is not published and the writer is told which rule it failed (the category selects a message the app already holds — nothing the model writes is shown), and a borderline review can be escalated to a person (pending_human). moderate-photo checks a dish photo is a photograph of food that plausibly matches the recipe before it is stored; a refused photo is never stored. Both fail closed: no key, an upstream error or an unparseable verdict means nothing is published and the user is told the check is unavailable, not that they were rejected. A person who believes a check was wrong can resubmit or write to the privacy address.
  3. A suggested start time for a new event. lib/scheduleLookup.ts looks a new event's title up against the group's own recent events (an exact title match first, then an embedding nearest-neighbour on agent-server) and pre-fills the start and end times. It never overrides a time the person has touched, every failure is silent, and the person can change the suggestion before saving. It is a suggestion about timing, not a write.

The first draft of this document said there was exactly one decision. Review found the other two: an automated-decision disclosure that leaves out content moderation is precisely the omission the Code's disclosure duty exists to prevent, so the list above is the honest one.

The deterministic result is the floor, always

AGENTS.md states the invariant this whole feature is built against, under "A Model May Choose WHO. It May Not Choose WHAT.":

ai-task-allocator returns { index, assigned_user_id } against a list the client computed and sent. It cannot invent, drop, retime or rename an item.

Concretely, in order:

  1. The app computes a complete allocation for every task and event first, using deterministic rules — who already has the most on this week, and what each person has said they can take on (lib/allocator.tsallocateTasksOptionC). That allocation is applied immediately; nothing waits on the model.
  2. The model is then asked, once, to refine it: it may reassign some items to a different household member. It is never shown the ability to add an item, remove one, change a date or time, or change a title — the request it receives does not include a way to do any of those things, so there is nothing to validate against because there is nothing to misuse.
  3. Every answer is validated before use. An assigned_user_id naming someone outside the household, or an index outside the range of items sent, is discarded, and that item keeps its deterministic assignment. A model call that is unavailable, over the household's weekly AI budget, slow, or simply wrong costs the household nothing — the schedule from step 1 is what ships either way.
  4. A person can change any of it. Both the deterministic assignment and any refinement the model made are ordinary rows in group_tasks / group_schedule_events. Reassigning, retiming or deleting one is the same action a household member would take on anything else on their calendar or task list, with no special "AI-assigned" state that resists being edited.

What it does not decide

Why this is easy to state honestly

Because the deterministic floor already exists and is already applied first, this disclosure does not have to describe a system that "usually" behaves a certain way, or hedge about edge cases. The floor computation and the validation of the model's answer are the same code path regardless of whether the model is called at all, is slow, or returns nonsense — so the sentence "the deterministic result is always the floor" is true in every one of those cases, not just the common one.

Keeping this true

If the allocator's contract ever changes — the model is given the ability to add or remove items, validation is loosened, or a second automated decision is introduced elsewhere in the app — this document, the in-app page, and lib/__tests__/automatedDecisions.test.ts all need to change in the same commit as the behaviour. A disclosure that quietly stops matching the code is worse than no disclosure, for the same reason AGENTS.md gives for privacy copy generally: it is read by someone deciding whether to trust the app with their household's or their child's information.