← All privacy impact assessments

PIA: child accounts, the guardian invariant and the child-safe variant

Status: Built — WS8 shipped 2026-09-08 (20260908043933); revised against the code the same day. Sections marked as built describe what the database and the server now do; §5.2 says which rows are structural, which are conventional, and which two are NOT built and stand in §11 as residual risk for the owner. §12A grades every Code requirement met / partly / deferred. Written: 2026-09-07 · Issues: #282 §4 (with #219 consent ledger, #220 child policy, #221 this register) · Workstreams: WS5 (schema, shipped), WS8 (behaviour, shipped), WS9 (the child-directed policy, shipped 2026-09-08) Nothing here is legal advice. Children's Code citations are to the exposure draft; section numbers may move on registration (due 10 Dec 2026).

Read 2026-09-ban-self-assessment.md first. This design is only lawful if the conclusion there holds: the Online Safety Act Part 4A has no parental-consent exception, so if GroupApp were an age-restricted social media platform, an under-16 account would be prohibited however carefully it was built.


1. Purpose and scope

What it is for. Children live in the groups this app organises. Today they appear only as subjects of records — a name on a task, a face in a photo, a baby with a feed log — and the privacy policy says in terms that they do not hold accounts. That is a real limitation: a thirteen-year-old with their own chores, their own place in the calendar and their own things to say in the family chat has no way to use the app, and the workaround is a shared adult login, which is worse for everyone.

The feature gives a child their own account, inside their own family's group, with a version of the app that is smaller by construction rather than by configuration.

In scope: how a child account comes into existence; what it can and cannot reach; who consents to what; what happens when guardians leave, are erased, or separate; and how a child ages out.

Out of scope, assessed elsewhere: the ban analysis (2026-09-ban-self-assessment.md); anything crossing a group boundary (cross-group-events.md); the baby tracker's own data (baby-tracker.md) and the photo wall's (photo-wall.md); the consent ledger's mechanics (#219, WS2); encryption (#223).

Not in scope and worth saying: this design does not make GroupApp a moderated platform. A group with a guardian in it is family, supervised — it is not platform, moderated. Adults in the group can post whatever adults post, and the app does not police it. That is what keeps the app out of the content-moderation business, and it is a limitation a parent should understand rather than a gap to be closed later.

2. Data involved

2.1 New collection

Kind Whose Children's? Sensitive? Free text?
user_birth_months.birth_month — a month and year, never a date of birth; a ROW of its own, not a users column, because every co-member reads the whole users row (WS5; AGENTS.md → A Birth Month Is A ROW) the account holder's yes, for a child no no
allowed_emails.child_of + allowed_emails.birth_month — the guardian who created the entry, and the month they declared, at the gate (as built: written by invite_child) the child's, linking to an adult yes no no
child_guardians rows — child ↔ guardian, plural both yes no no
groups.founder_assured_at / founder_assured_by — when and by what method a group's founder was assured to be an adult the founder's no no no
groups.children_allowed — tri-state (undecided / yes / no) (as built) the group's no no no
A consent ledger row per act, with given_by_kind (self / guardian / group_admin); as built two purposes: child_account (the guardian's) and child_account_assent (the child's) the consenting person's sometimes no no

Birth month, not date of birth. A month is enough to derive every threshold this design uses — 13, 15, 16, 18 — and a full date of birth is a stronger identifier for no gain. This is minimisation with a concrete payoff rather than a gesture: a leaked birth month is close to useless for impersonation, and a leaked date of birth is not.

No age verification data of any kind. No government identification, no Digital ID, no document upload, no biometric estimate, no third-party assurance provider. Two reasons: it would be disproportionate to the risk (§8), and it is precisely the class of collection the Act's 63DA/63DB singled out as not required of even an age-restricted platform.

2.2 What a child account then holds, that any account holds

Chat messages, task completions, calendar entries, photos they post and photos they appear in, game state, their display name and avatar colour, push tokens, and — where they use the parts of the app that have them — read receipts and reactions. All of it is a child's personal information under the Code (a child is anyone under 18, not under 16).

2.3 What is deliberately not collected

3. Flows and locations

Data Device Supabase (Sydney, ap-southeast-2) GCP (australia-southeast1) Model provider
Birth month, guardian links, child flag entered by the guardian stored; read inside RLS predicates no no
A child's chat, tasks, photos, games written and read on the child's device stored, RLS-scoped to the group no no — the child's own surfaces have no AI
Founder assurance (Door A, planned) web, not the app groups.founder_assured_* no no
Card details for the $0 SetupIntent (planned) web never — Stripe holds them no no
Consent ledger rows stored no no

No new boundary crossing. Everything this feature adds stays inside Supabase's Sydney project. The adults in a child's group continue to use the assistant, the insight and the allocator, and those surfaces continue to send group data to a model under the existing consents; what changes is that the child's own account never does, and that the group's task and calendar data — which is about children by nature — is being moved to Sydney inference under WS20 (planned).

One flow to state plainly because it is easy to miss. A child's data still reaches a model when an adult asks the assistant about the group: a task titled "Ada's dentist, 3pm" is a child's personal information in an adult's request. Removing AI from the child account does not remove children from AI. WS20's rule — group data is processed in Australia — is what addresses that, and the transparency copy must not imply otherwise.

4. How an account comes into existence: assurance once, declaration per child

An earlier draft put an age question at every join. That conflated two different things, and separating them is most of this design.

Assurance Declaration
Question Is there a real adult responsible for this group? Which members are children, so the right rules apply to them?
When Once, at group founding When an adult creates a member's entry
How Today: the owner manually allowlists someone he has met and knows to be an adult. Planned (Door A, #282 §2, growth-triggered): a $0 Stripe SetupIntent plus a birth-month declaration on the web. Either way recorded on groups.founder_assured_at / _by. One checkbox: "This person is under 16. I am their parent or guardian." No verification.
Serves The ban: a child cannot found a group, and a founder was assured The Code: guardian consent (s 13), the child policy (s 23), the child-safe variant, PIA scope
Fails how A card is possession, not age — some Australian banks issue debit cards from 14. Reasonable steps, not proof. A guardian declares an age wrongly. Bounded by: children cannot invite anyone, and every inviter is inside an assured group.

Why not per-member checks. They would age-verify every member of every family to catch a rare misuse; that fails minimisation, it puts an identity check between a parent and their family calendar, and it is what the Code's s 8(5) posture explicitly lets a service skip by applying child-level protections to everyone instead. The failure mode being defended against is a group founded for the wrong purpose, so the group is the right place to check. If teen-only groups appear as a real pattern, the escalation is a stronger assurance method at founding — never per-member checks (ban self-assessment §9).

The existing choke point does the work. enforce_email_allowlist_on_signup (20260808150000) already means nobody enters without an existing member creating their entry. Child status becomes a property of that entry, stamped at the door, unbypassable by any code path — which is why child accounts can ship under the current invite-only regime and do not wait on open sign-up. Never add a bypass to that trigger while this is in flight; the project depends on it being the only door.

5. Age bands and the child-safe variant

5.1 Bands

Three legal thresholds apply to the same person and they do not line up. Storing a birth month and deriving flags at read time — is_under_16(uid), is_under_18(uid), usable inside RLS predicates — means nobody ages out by cron job.

Age What they are What that means
0–12 Profile, no login. Modelled the way group_babies is today: a name and an avatar the group holds. Chores and screen time can be assigned to them by a parent. No account, so no policy to show them, no consent to obtain from them, no ban question to answer. This is deliberately the default for young children rather than a lesser account.
13–15 Child account. The guardian creates the entry and consents; the child assents. The child-safe variant applies, enforced by the database. Under 15 the guardian holds every consent (s 13). At 15 the child may hold their own — the OAIC's presumption of capacity — but the variant does not change, because the variant is about the ban and the Code's protections, not about who clicks "I agree".
16–17 Young person. Outside the ban, inside the Code. The full app, but AI and voice off by default and enabled only by the young person's own consent with the cross-border notice. Guardian link retained to 18. The child-directed policy is still shown. Every Code obligation runs to 18.
18+ Adult. On the eighteenth birthday month the guardian link lapses and the account is ordinary.

13 is a floor chosen, not derived. No Australian instrument sets it; it is the conventional minimum across comparable services and it keeps the app clear of the youngest cohort, for whom the profile model is the better answer anyway. It is a decision the owner can move, and if it moves the reasoning here moves with it.

5.2 The variant, by surface — as built (2026-09-08)

The column that matters is the last one. Structural means the database or the server refuses it whatever the client does; conventional means the app hides or declines to offer it and a different client would not; not built means exactly that, and the row is carried into §11.

Surface Under 16 gets Enforced by Structural or conventional
Assistant, dashboard insight, task allocation Nothing. Fails closed. The dashboard shows the deterministic fallback brief; allocation is the deterministic floor. agent-server reads is_child_account through the caller's own client on every request to /api/agent, /api/baby/summary and /api/ceremonies/facilitate (the ceremony still runs — deterministic script) and refuses before anything is built or billed; an RPC error is a refusal (agent-server/src/childAccount.ts, pinned by checks/childAccount.check.ts). generate-dashboard-insight and ai-task-allocator answer 403 child_account the same way. Restrictive policies on chat_sessions and chat_messages refuse the transcript rows the typed screen would write. The Assistant tab is ALSO hidden (href: null), which is the courtesy and not the enforcement. Structural
Voice grants Cannot be created; a grant paired before the month was recorded stops working on the next turn A restrictive INSERT policy on voice_grants; /api/voice/grants refuses the pairing call; /api/voice re-reads the predicate for the grant's owner on every turn and records the refusal as a turn. The Voice row is hidden in Settings. Structural
Baby tracker Unchanged — the child reads and writes it as any active member does. Nothing. Not in WS8's brief; no policy on group_babies, baby_logs, baby_feed_sessions keys on the child predicate. NOT BUILT — §11
Public plan reviews, dish photos Unchanged — a child can submit a review and a dish photo. Nothing. submit-review and moderate-photo do not read the predicate. NOT BUILT — §11
Photo wall Yes. No likes at all — no heart, no names, no count — and that is true for every user, not a child restriction (WS21, shipped 2026-09-08). Shipped
Chat, tasks, calendar, games, ceremonies, intentions, thanks Full. This is the app for them. Proved: a child in the same group posts to the chat, creates a task and an event, and writes a plan nobody else can read. The guardian invariant is the safety property, not a feature restriction. The question bank and check-ins are deterministic for everybody (WS22), so the child's motivation layer is the same surface, not a reduced one. Structural (the invariant), and no restriction to be conventional about
Group founding, invites, member admin None create_group_secure refuses an under-18 founder (GRP08); generate_group_invite, approve_join_request and reject_join_request refuse an under-18 (GRP10); invite_child is adult-only. Three admin RPCs the client calls do not exist at all (AGENTS.md → Known Issues, 2026-09-08) — a gap in the app, not in the gate. Structural
Cross-group event invitations (WS6, shipped) Cannot send, preview or redeem. Sees the event on their own group's calendar once an adult accepts. Every RPC refuses is_under_18 with code: 'under_18' (20260908022755); the tables are RPC-only with no client grant, so there is no table path to add a policy to. The event-code chip is hidden on a child account. Structural
Consents A child under 15 holds none of their own except their assent A restrictive INSERT policy on consents: no self row from an under-15 for any purpose but child_account_assent. At 15 the presumption of capacity applies and the policy stops matching; the variant above does not move. Structural

What this variant is for, corrected 2026-09-08 against eSafety's guidance. It is a privacy-Code measure — strictly-necessary-by-default collection (s 9), best interests (ss 10–11) — and a harm-reduction measure. It is not part of the argument that GroupApp is outside the under-16 ban: the guidance's Step 7 says age-based restriction of social features "is not to be given any meaningful weight" in the purpose test. The ban question is answered by how every member uses the service.

Updated 2026-09-08. That paragraph's last sentence used to read "and the ban self-assessment's §7A stocktake is the gate on this feature". It is not, any more. The app is outside the under-16 rule at the features step — no recommender feature and no logged-in feature — so s 63D does not bind it and the stocktake gates nothing (ban self-assessment §§5.5, 7). Everything else here is unchanged: the variant is still justified on Code and harm-reduction grounds alone, and it still contributes nothing to the ban argument.

Two implementation rules that are the whole point:

An open question this document raises and does not answer. ANSWERED 2026-09-08, and not the way this section framed it. The question was whether a child account should lose attributed likes, message reactions and read receipts — each a "feedback feature" within Rules s 4A(5)(a) — which would have made the child experience free of every feature the Rules name. It noted the cost: a thirteen-year-old's messages silently not showing as read while everyone else's do, a strange unexplained asymmetry inside one family chat.

The owner removed all three for EVERY member instead (WS21 — ban self-assessment §5.3). Two things follow, and the second is the more useful lesson:

6. The guardian invariant, and the edges where it hurts

The invariant: a child account is active only in a group where at least one of their guardians is active. A group_members trigger, not a client check. This is the one guarantee in the design that is absolute, and it is why child_guardians is a table rather than a column — separated parents are the ordinary case, not an edge, and a child is active in any group where any of their guardians is active. Co-parenting across two homes is a child in two standing groups with one guardian in each.

The initial schema had a child member role, migrated away on 2026-07-25. Do not resurrect it. Child-ness is a property of the person, not of one membership.

Departures are the hard part, and they are where a bug hurts a child. Every one of these is a fail-closed refusal, in the same family as delete-account failing closed on the erasure ledger:

What the invariant does not do. It does not make the group safe. It does not review what adults post. It does not mean a guardian is watching. It means there is always a responsible adult present who chose to be there and can act.

As built (2026-09-08). enforce_guardian_presence on group_members (20260908043933): a guardian's row cannot be deleted or moved off active while a dependant under 18 in that group would be left with no other active guardian (GRP06, "Remove from the group first." — the service role is refused too); a child cannot be inserted or activated where no guardian of theirs is active (GRP07); request_join_group returns no_guardian / children_not_allowed before writing anything, uncharged. delete-account refuses a guardian with a live dependant (409, in words, before the storage sweep) and is the one place a LAPSED link — a child now 18 — is removed, because the FK cannot tell lapsed from live. The lapse itself is a predicate (is_under_18), never a sweep; the child_guardians row stays as a record. "The young person is told" at graduation is not built: nothing notifies anybody when a month rolls somebody past 18 (§11). Separated parents work as designed: the child's join request into a second group succeeds once any guardian is active there (proved in __tests__/child_accounts_rls.test.ts).

7. Groups, not households — and children_allowed

Say "group", never "household". The app is about groups: co-parents, polycules, blended families, share houses, carer teams. "Household" imports one dwelling and one family shape, and it conflates three things the schema keeps apart:

Axis Column Rule
What a group calls itself groups.type (exists: Family, Couple, Extended Family, Share House, Housemates, Team, Group) Self-description and copy only, rendered through groupNoun() (lib/groupTypes.ts). Never an eligibility rule, never sent to a model, and never extended with labels that encode relationship structure — a stored "polycule" is sensitive information the app has no need to hold. "Group" stays the catch-all so nobody must name their arrangement.
What a group is for, and how long it lasts groups.kind (planned: standing, event) Behaviour, never a label. See cross-group-events.md.
Who founded it founded_by, founder_assured_at / _by (planned) A property of any standing group

Children per group is a switch, not a type: groups.children_allowed, tri-state (undecided / yes / no). A consent-class group setting: admin-only by trigger, announced in the group chat, and refused if turned off while a child is a member. The group's type suggests the creation default only — on for Family, Extended Family, Couple and Group; off for Share House, Housemates and Team — and a guardian adding the first child to an undecided group is offered the switch in the same flow, so "the group allows children" and "this guardian is adding one" are one screen rather than two.

Why a switch rather than a type. A share house that is also three friends co-parenting is a real arrangement, and a type-based rule would refuse it while a family group that has become a flat-share would silently keep permission it no longer wants. The switch is a decision someone made, attributable and announced; a type is a label someone picked at signup.

As built (2026-09-08). groups.children_allowed is the fourth consent-class group setting in lib/settingsScope.ts: owner/admin only by trigger (GRP04, with the app.consent_sweep arm on the admin check), announced by announce_setting_change in three sentences ("decided that children can be in this group"), and refused with GRP05 naming the child when set to no while an under-18 is a member — that refusal is NOT armed, so no process can flip it over a child's head. The type suggests the creation default in lib/childAccounts.ts only. The "same screen" is Manage Group → Children (components/Group/ChildrenSection.tsx): the three pills, the children and their guardians, and the add-a-child sheet, which offers the switch to an admin when invite_child answers children_not_allowed.

The privacy policy's "children do not hold accounts" became false the day this shipped, and the one sentence was corrected in the same PR (constants/legalTexts.ts §4 now describes child accounts and points at the child's page). The child-DIRECTED policy (s 23) shipped as WS9 (2026-09-08): CHILD_PRIVACY_POLICY, agreeing word for word with the child's page wherever they overlap (both are built from childPrivacySections); §12A now records that as met.

8. Risks and mitigations

Risk Who is harmed Mitigation Structural or conventional Residual
A guardian declares a 14-year-old as an adult, deliberately or carelessly, and the child gets the full app including the assistant the child The declaration is made by the person who knows; children cannot invite anyone, so a misdeclaration cannot propagate; every inviter sits inside an assured group Conventional — a checkbox Accepted. §11
A group is founded by a 15-year-old using a debit card children in that group; the app's ban position Founding assurance (§4); today, manual allowlisting by someone who has met the person Assurance is structural (a recorded column); what it proves is conventional Accepted; escalation is stronger assurance at founding
A teen-only group forms and the app becomes what the ban was written about the app, and the children in it The child cannot found or invite; the guardian invariant; the per-group count metric (ban §9) Invariant: structural. Detection: conventional Accepted, with monitoring
A child's data reaches a model the child The child account has no AI surface, failing closed, re-checked server-side each turn Structural once WS8 ships An adult's request about the group can still carry a child's name (§3). Addressed by WS20's Australia rule, not eliminated
A guardian leaves and strands a child the child Trigger-enforced refusal (§6) Structural
Guardian erasure orphans a child the child, and the departing adult Fail-closed dependant check Structural An adult's erasure is delayed by a step. Accepted deliberately
A separated parent uses the group to monitor the other parent through the child an adult; potentially the child Nothing in this design. The app has no location, no activity feed, and no per-member behavioural surface, so the material to monitor with is thin Conventional (an absence) Accepted, and named. The app should never gain a per-member activity view
A shared, unlocked phone means the child account is used by an adult or a sibling the child Nothing. No app fixes this Accepted. §11
An adult in the group posts something a child should not see the child Nothing — this is family, supervised, not platform, moderated (§1) Accepted and stated to parents
A child's record outlives their interest in it — years of chores, chat and photographs the child, later Per-item deletion exists; erasure by the child or a guardian (s 32); the retention sweeps that exist Partly structural Accepted. §10 has the reasoning

9. Legal basis and consents

The consent ledger (#219, WS2) is planned. Until it ships there is no record of a consent act for anything except the terms acceptance already on users; the current state lives in switch columns. This feature must not ship before the ledger, because a guardian consenting on a child's behalf is exactly what the ledger's given_by column exists to record.

Purpose Who gives it for a child Notes
child_account (as built) The guardian: subject the child, given_by_kind = 'guardian', admitted by policy only where child_guardians links the two and the child is under 18. Twelve months; the existing sweep expires it. Recorded from app/child-consent.tsx, a screen the guardian went looking for. The s 13(2)(b) reasoning is on the screen, and it says "we have not verified". A guardian may READ a dependant's consents (a new SELECT policy) — otherwise the row they wrote would be invisible to them.
child_account_assent (as built) The child, as their own self row — the ONE self purpose an under-15 may write. Separate purpose rather than a new action, so the latest-row view cannot let one mask the other. Recorded from the child's page by "I have read this". It gates nothing and says so.
terms 13–15: the guardian's child_account stands for it; the child's own terms row at signup is refused by the under-15 policy and tolerated by the signup screen. 16–17: the young person. The child-directed policy (#220, WS9) shipped 2026-09-08 as CHILD_PRIVACY_POLICY — §12A.
assistant, voice, on_device_brief Not available under 16 at all — there is nothing to consent to. 16–17: the young person's own, off by default. Removing the surface is better than obtaining consent for it.
baby_summary_to_model The group's admins, who are the parents by construction Group-scoped, admin-only. Not a child-account consent.
read_receipts No writer since 2026-09-08. Read receipts were removed for every member (WS21); the purpose stays in the closed list because a purpose that was consented to is a fact and the list mirrors a CHECK constraint. Nothing asks for it, and the expiry sweep flips a column nothing reads.
overseas_processing (planned, WS16/WS20) Where a child account is present, one of the child's registered guardians must be among the two confirmers, enforced in the approval RPC The ledger row records that it was given on the child's behalf
cross_group_events (planned, #331) Never a child — under-18s cannot redeem See cross-group-events.md

Consent must be voluntary, informed, current, specific and unambiguous, must not be bundled (s 14(3)(b)), and expires at twelve months (ss 15–16). Withdrawal is one tap (s 17). A personal stance preset may set preferences and never consents — a consent is always an individual prompt on a screen a person went looking for.

What the child is told (the s 33 posture) — as built. app/child-privacy.tsx, "What your parent can see", the first row of Settings on an under-16 account and reachable whenever they want it: what is kept, why, who sees it, what is only theirs (their plan; the absent assistant conversation; the chat being the group's), what a guardian can do (take the yes back, remove them, ask for deletion; the admin's children_allowed, announced to the whole group; and that the app does not tell a parent what they looked at), how long, and the s 32/36 route they may use themselves. Two sections are GENERATED from lib/settingsScope.ts so the page cannot promise a privacy the switches do not keep. Written for a ten-to-twelve-year-old and scanned for overclaims. It is not shown at setup — there is no child setup flow yet; the deviation from this paragraph's last sentence is recorded in §12A (s 33 "as soon as in use": partly met).

10. Best interests of the child (exposure draft s 10)

What a child gets. Their own place in their family's organisation: their own chores, their own view of the calendar, their own voice in the group chat, their own account rather than borrowing a parent's. That is not a trivial good. A thirteen-year-old who can see that Thursday is their turn, and tick it off themselves, is being treated as a participant in the household rather than a subject of it. The games hub's per-user presentation and the ledger-visible parent adjustments already fit that shape.

What it costs them. An account is a record. Chat messages, completions, photographs and game history accumulate under their name from thirteen, and they did not choose the retention policy. They are in a space their parents administer and can read. And the app is being made attractive to exactly the age group a national law has just decided should not be on social platforms — which is a reason to be careful, not a reason the app is one.

What the safer design would have been, and why it was not chosen. The safest design is the one that exists today: no child accounts, children as profiles only. It was not chosen because it is not actually safer for the child — it produces shared logins, which are worse for the child's privacy from their siblings and their parents' contacts than an account of their own, and it excludes teenagers from a tool their family runs on. The second-safest is a read-only child account, which was not chosen because a child who can see the chores but not tick them is being shown their obligations without any of the agency, which is the wrong lesson.

Where the child's interests and the parent's diverge, and who won.

The graduation design is a best-interests decision too. A child ages into more of the app rather than being handed all of it at 16 or having a switch flipped by a parent. Sixteen is outside the ban but still inside the Code, so the young person gets the full app with AI off by default and their own consent to turn it on — their decision, informed, and reversible.

11. Residual risk accepted by the owner

Added as built, 2026-09-08 — each is a thing the owner is accepting by merging, written plainly:

12. Review trigger

12A. Requirements confirmed against the exposure draft (read 2026-09-08) — graded as built

Read from docs/sources/oaic-childrens-online-privacy-code-exposure-draft.pdf. Each is a concrete obligation the child-accounts work must carry, with the section it comes from, and — after WS8 — whether it is met, partly met or deferred, and where.

13. Sources

Primary: exposure draft of the Children's Online Privacy Code (ss 8, 10, 13, 14, 15–17, 23, 26, 28, 32, 33, 38–39) as summarised in docs/privacy_posture.md §4.2 — the exposure draft itself has not been re-read for this document, so every section number here is as good as that summary and no better. Online Safety Act 2021 Part 4A and the Rules, verified — see 2026-09-ban-self-assessment.md §14.

In repo: supabase/migrations/20260808150000 (the signup allowlist trigger); constants/legalTexts.ts (the sentence that changes); lib/groupTypes.ts (groupNoun); AGENTS.mdInvite-Only Is Enforced In The Database, Check RLS Is ENABLED Before Writing Policies, Ship The Retention JOB Before The Retention CLAIM; docs/privacy_posture.md §5; issues #282 §4, #219, #220, #221.

Built (2026-09-08): supabase/migrations/20260908043933_ws8_child_accounts.sql; __tests__/child_accounts_rls.test.ts; lib/childAccounts.ts, lib/childVisibility.ts, lib/consents.ts; app/child-privacy.tsx, app/child-consent.tsx, components/Group/ChildrenSection.tsx; agent-server/src/childAccount.ts; supabase/functions/delete-account, generate-dashboard-insight, ai-task-allocator. Also built (WS9, 2026-09-08): CHILD_PRIVACY_POLICY and the guardian's-view paragraph in constants/legalTexts.ts; lib/__tests__/childPrivacyPolicy.test.ts; the Legal section in app/settings.tsx; the policy links in app/child-privacy.tsx and app/child-consent.tsx; site/build.mjs's /privacy/children page. Not built: the two §5.2 rows marked so, and everything in §11's "added as built" list.