Module-boundary guard: domain stays Android-free and ads cannot reach cycle data #7

Closed
opened 2026-08-18 02:14:37 -05:00 by null · 0 comments
Owner

Two boundaries in this project are load-bearing, and both are currently held up by nothing but the fact that the offending code has not been written yet.

  1. domain/* must not see the Android SDK. It is kotlin("jvm") today, so this half is already a compile error — but a future contributor converting it to com.android.library to get one convenient API would remove that guarantee with no test failing.
  2. The ads subsystem must never reach cycle data. PRODUCT_PLAN.md §34 states it as non-negotiable: no menstrual date, cycle length, fertility status, ovulation estimate, prediction confidence, prediction history or spotting record may reach advertising, ever.

Build a Gradle check that enumerates each module's permitted dependencies from the table in docs/architecture/README.md and fails the build on anything outside it. Wire it into ./gradlew check.

The guard is not finished when it passes. docs/architecture/GUARDS.md §1: a guard nobody has seen fail is not yet evidence. Add a deliberate forbidden dependency — domain/prediction on app, say — watch the guard go red, then restore the file. scripts/prove-guard.sh does exactly this with a trap so the file comes back even if the run dies.

Why now rather than in Batch 07 with the ads module: a guard written before the code it constrains is a guard that was never shaped around an exception somebody wanted to make.

Verify: bash scripts/prove-guard.sh shows the guard failing on an injected forbidden dependency and passing after restore, and ./gradlew check runs it.

Two boundaries in this project are load-bearing, and both are currently held up by nothing but the fact that the offending code has not been written yet. 1. **`domain/*` must not see the Android SDK.** It is `kotlin("jvm")` today, so this half is already a compile error — but a future contributor converting it to `com.android.library` to get one convenient API would remove that guarantee with no test failing. 2. **The ads subsystem must never reach cycle data.** PRODUCT_PLAN.md §34 states it as non-negotiable: no menstrual date, cycle length, fertility status, ovulation estimate, prediction confidence, prediction history or spotting record may reach advertising, ever. Build a Gradle check that enumerates each module's permitted dependencies from the table in `docs/architecture/README.md` and fails the build on anything outside it. Wire it into `./gradlew check`. **The guard is not finished when it passes.** `docs/architecture/GUARDS.md` §1: a guard nobody has seen fail is not yet evidence. Add a deliberate forbidden dependency — `domain/prediction` on `app`, say — watch the guard go red, then restore the file. `scripts/prove-guard.sh` does exactly this with a trap so the file comes back even if the run dies. Why now rather than in Batch 07 with the ads module: a guard written before the code it constrains is a guard that was never shaped around an exception somebody wanted to make. Verify: `bash scripts/prove-guard.sh` shows the guard failing on an injected forbidden dependency and passing after restore, and `./gradlew check` runs it.
null added this to the Batch 01 — Foundation milestone 2026-08-18 02:14:37 -05:00
null closed this issue 2026-08-18 03:00:14 -05:00
Sign in to join this conversation.
No Label
P0
P1
P2
release-blocker
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: null/Privacy-Period-Tracker#7
No description provided.