# 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) |
| 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; `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. `dist/` — the onboarding illustration sources, and `splash.png`, the lockup `docs/data/img/logo.webp` and `banner.webp` are generated from |
| `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: <who maintains this>
Last reviewed: <YYYY-MM-DD>
Governs: <paths or subject this document is authoritative for>
Review trigger: <the change that should send someone back to this file>
Fires on: <optional — added, deleted, moved, changed>
```

**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: <the path> — <why, in a few words>
```

**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.
