# Doc Trust Map — which document to believe ``` Status: Current Owner: _null Last reviewed: 2026-08-18 Governs: docs/** Review trigger: Any doc added, deleted or moved; any change to which doc owns a subject Fires on: added, deleted, moved ``` > Written last, and describing what is **actually here** rather than what the > template said should be. Its whole value is being accurate about the others. ## Work items are not in this tree The sequence of work, the open defects, and the things blocking a release all live in this repository's **issue tracker** at [dream.scheller.ltd/null/Privacy-Period-Tracker](https://dream.scheller.ltd/null/Privacy-Period-Tracker), not in `docs/`. Milestones are batches — eight of them, `Batch 01 — Foundation` through `Batch 08 — Polish` — issues are deliverables, and severity labels are `P0`, `P1`, `P2` and `release-blocker`. This section exists to stop the next contributor starting a fresh markdown to-do list. A list of things to do in two places is two records that will disagree, and nothing will say which one is right. | Question | Answer lives in | | --- | --- | | What are we building, and for whom? | [`planning/PROJECT_PLAN.md`](planning/PROJECT_PLAN.md) | | What exactly does V1 do — prediction rules, screens, copy, compliance? | [`planning/PRODUCT_PLAN.md`](planning/PRODUCT_PLAN.md) | | What is the sequence of work? | milestones in the tracker | | What is left in this batch? | open issues under that milestone | | What is broken right now? | issues labelled `P0` / `P1` / `P2` | | What makes a release wrong? | issues labelled `release-blocker` | | What is the next action? | the `nextAction` field on the project at privacyllc.dev — the newest entry in [`history/DEVELOPMENT_LOG.md`](history/DEVELOPMENT_LOG.md) says what it was *then* | | What is blocking us? | the tracker, for the work; the blockers table at privacyllc.dev, for the stakeholder-facing version | | What do I do when a piece of work is finished? | [`WORK_CYCLE.md`](WORK_CYCLE.md) | | What happened, and when? | [`history/DEVELOPMENT_LOG.md`](history/DEVELOPMENT_LOG.md) | | Why is it built this way, and what was rejected? | [`history/HISTORY.md`](history/HISTORY.md) | | Did QA pass, and what does the tester think? | [`qa/ClaudeReport.md`](qa/ClaudeReport.md) | | What did QA actually reach? | [`qa/ClaudeQACoverage.md`](qa/ClaudeQACoverage.md) | | What is a QA round? | [`qa/ClaudeQAPlan.md`](qa/ClaudeQAPlan.md) | | How is it built — modules, boundaries, data shapes, migrations? | [`architecture/README.md`](architecture/README.md) | | Which constants are claims about bodies, and on what evidence? | [`architecture/SCIENCE.md`](architecture/SCIENCE.md) | | What should it feel like, and what words does it use? | [`design/README.md`](design/README.md) | | What colour, logo or type do I use? | [`design/BRAND_GUIDE.md`](design/BRAND_GUIDE.md) — it outranks [`planning/PRODUCT_PLAN.md`](planning/PRODUCT_PLAN.md) §39 where they differ | | What is protected, from whom, and what must never be logged? | [`security/SECURITY.md`](security/SECURITY.md) | | What is checked before a Play release? | [`security/SECURITY_CHECKLIST.md`](security/SECURITY_CHECKLIST.md) | | Which script do I run, and can it stop me? | [`TOOLS.md`](TOOLS.md) — the signpost; [`architecture/README.md`](architecture/README.md) has the table | | What runs before a commit? | [`architecture/githooks/README.md`](architecture/githooks/README.md), and the hooks themselves in `.githooks/` | | How do I write a check that will actually catch something? | [`architecture/GUARDS.md`](architecture/GUARDS.md) | **Next action and blockers are recorded at the end of every piece of work, not when somebody asks.** [`WORK_CYCLE.md`](WORK_CYCLE.md) holds that procedure and the reason each step is in it. ## The two planning documents, and which owns what Unusually, this project has two — worth stating plainly, because a reader who does not know which is which will pick the wrong one. | | Owns | Length | | --- | --- | --- | | [`planning/PRODUCT_PLAN.md`](planning/PRODUCT_PLAN.md) | the **V1 specification**: prediction requirements and their acceptance cases, the data model, every screen and its copy, notification modes, monetization, artwork, Play compliance | ~2,500 lines | | [`planning/PROJECT_PLAN.md`](planning/PROJECT_PLAN.md) | the **argument**: what this is, who for, what it deliberately is not, the stack and the reason for each choice, what success looks like, known risks | ~110 lines | `PRODUCT_PLAN.md` is the document this project started as — it existed before the repository did. Everything else in `docs/` points **into** it rather than copying out of it, and that is deliberate: a second copy of a fertility disclaimer or a notification string is how two versions of a promise come to exist. `architecture/`, `design/` and `qa/` each name the sections of it they own. Where the two disagree, `PRODUCT_PLAN.md` is the specification and `PROJECT_PLAN.md` is the reasoning — resolve it rather than letting both stand. ## Folder layout | Folder | Contents | | --- | --- | | `docs/planning/` | `PRODUCT_PLAN` — the V1 specification. `PROJECT_PLAN` — the vision. Neither is the schedule; that is the tracker. | | `docs/qa/` | `ClaudeQAPlan` (playbook, passes A–H), `ClaudeQACoverage` (what each pass reached), `ClaudeReport` (the verdict) | | `docs/architecture/` | modules, boundaries, data shapes, the migration table; `SCIENCE.md` — the physiology constants and their citations; `GUARDS.md`; `githooks/README.md` | | `docs/design/` | `README.md` — tone, the four rules that settle arguments, and which specification sections own each surface. `BRAND_GUIDE.md` — the owner-supplied visual identity, which outranks `PRODUCT_PLAN.md` §39 on colour. `brand/` — the owner's source art, including the emblem the launcher icon is cut from and the Play listing exports. `dist/` — the onboarding illustration sources, and `splash.webp`, the lockup `docs/data/img/logo.webp` and `banner.webp` are generated from. `screenshots/` — captured app screenshots, for the product page on privacyllc.dev and the Play listing | | `docs/security/` | `SECURITY` — threat model, the advertising boundary, logging rules. `SECURITY_CHECKLIST` — the pre-release list | | `docs/history/` | `DEVELOPMENT_LOG` (dated, append-only), `HISTORY` (decisions and their reasons), `BATCH_LEDGER` (archived) | | `docs/data/` | `README.md` — the rule, and why this folder cannot be exempted. `img/README.md` — the three required names, their dimensions and the 512 KB ceiling. `img/icon.webp`, `img/logo.webp`, `img/banner.webp` — the marks privacyllc.dev renders | | `docs/` root | this map; `WORK_CYCLE`; `TOOLS` | `README.md` stays at the repository root; it is the landing page and moving it breaks that. Everything else lives under `docs/`. ## What this project deliberately does not have Recorded here because an absence somebody chose and an absence nobody noticed look identical from outside, and only one of them is fine. - **docs/OPERATIONS.md — deleted.** Named without backticks, because `doc-claims.sh` reads a backticked path as a claim the file is there and this one says the opposite. Privacy: Period Tracker is an offline-first Android app distributed through Google Play. There is no host, no container, no uptime and no restore path of ours. An empty runbook reads as one nobody wrote rather than one that never applied. - **docs/planning/FUTURE.md — never created**, and named bare for the same reason. The Command Center's docs report looks for a batch ledger there and reports it **missing** for every tracker-first project. That is the expected state; creating the file to turn the line green would rebuild the second record [`history/BATCH_LEDGER.md`](history/BATCH_LEDGER.md) was archived for. - **Most of the template's scripts.** Six were taken; the rest assume a deployed Node or Postgres service. [`TOOLS.md`](TOOLS.md) names each one and why. `doc-claims.sh` noting a document that mentions a script this project does not have is expected, not a failure. - **A master copy of the hooks under `docs/architecture/githooks/`.** The template keeps one and installs copies; this repository keeps only `.githooks/`, because `pre-commit` here is adapted for Gradle and a second copy would drift. - **No `Exempt:` declarations.** Every document this convention asks for is either present in git or listed above as deliberately deleted. ## Source-of-truth ladder When two sources disagree, believe them in this order: 1. **Verified code behaviour** — read the source, run `./gradlew test` 2. **The issue tracker** — for anything about state of work: what is open, what closed, when, and by which commit 3. **Specialist docs** — authoritative for their own subject only 4. **History and logs** — a record of *then*, not a description of *now* A document that describes work as done is describing what was true when it was written. The tracker is describing now. The `Status:` table in [`../README.md`](../README.md) is the one place a claim about what is built is allowed to live, and every row of it cites its evidence. ## The status header Every document in this tree opens with one, immediately after its H1 — and so do the documents at the repository root, which `scripts/doc-triggers.py` reads alongside this tree. ``` Status: Current | Draft | Superseded | Archived Owner: Last reviewed: Governs: Review trigger: Fires on: ``` **Exactly those four status words.** A checker reads them, and a document whose status falls outside the list is reported as having an unknown one rather than being quietly accepted. **Review trigger** is the line that matters. "Last reviewed" ages on its own and a reader cannot tell a current document from an abandoned one by looking at it; a trigger names the event that should bring somebody back. It is also checked: a header carrying `Status` without `Review trigger` is reported as incomplete — that combination looks finished and is not. **Governs** is a comma-separated list, and an entry may explain itself after the glob with a **spaced dash** — `docs/data/** — the assets privacyllc.dev renders`. `scripts/doc-triggers.py` cuts the entry there and reads the globs from the left. **Use that form and no other.** A gloss in parentheses, or after a colon, is not recognised: the whole entry becomes the glob, matches nothing, and the document is silently never fired — not reported as skipped either, because it still looks like a path. **Fires on** is optional and only for the case where `Governs:` is much broader than the trigger. This file is the extreme of that gap: it governs `docs/**`, the broadest glob here, while its trigger is one of the narrowest. Omit the line unless it is genuinely needed — absent means fire on every kind, which is what almost every document wants. ## Declaring a document deliberately absent A repository may decide it will not keep one of these documents in git. Say so **here**, one line per path, anywhere in this file: ``` Exempt: ``` **Write the real path only when you mean it.** Outside a fenced block, an `Exempt:` line naming a real document is not an example — it is a declaration, and the checker will report that document as deliberately absent. Keep illustrations fenced, and use placeholders anyway, as the form above does. This repository currently declares none. Where a document is genuinely not applicable it has been **deleted** and recorded above instead, which is the honest form: an exemption says "kept elsewhere", and `OPERATIONS.md` is not kept anywhere. **`docs/data/` and `docs/data/img/` cannot be exempted.** A declaration naming either is refused rather than honoured, because the Command Center renders what is in them — an exemption would produce a project card with no icon and nothing explaining why. If one of them is ever missing, the mechanism is a filed issue — [`data/README.md`](data/README.md) says what to file and why a placeholder is worse than a gap — never an exemption.