Commit Graph

2 Commits

Author SHA1 Message Date
null f5e9fbe53c feat: module boundary guard, and two API-level bugs it uncovered
checkModuleBoundaries holds the dependency tables in docs/architecture/README.md
as a check: every module's permitted project dependencies, plus the rule that
domain:cycle and domain:prediction must never apply an Android plugin. core:ads
is already in the map with an empty permitted set, before the module exists —
PRODUCT_PLAN.md §34 is non-negotiable, and a guard written alongside the code it
constrains is one shaped around whatever exception somebody wanted at the time.

It lists every violation rather than the first, and refuses to report a pass
when it examined no modules at all.

THE GUARD FAILED ITS OWN FIRST PROOF

prove-guard.sh injected a forbidden dependency into :domain:prediction and the
guard reported "7 modules checked, no violations". The root project is
configured before its subprojects, so reading subprojects.configurations from
the root script saw every configuration empty — it had been green over an empty
map since the moment it was written, and would have been trusted for months.

Collection moved into afterEvaluate, and the task now throws rather than passing
if it ends up with no modules. Three proofs recorded in the architecture doc,
all re-run and all red: a domain module reaching upward, :app reaching past the
repository straight to Room, and a module with no rule being reported as
unmeasured rather than assumed fine.

TWO REAL BUGS FROM WIRING IT INTO `check`

Running the whole check for the first time turned up Android lint errors that
would have shipped:

  NewApi: java.time.LocalDate#ofInstant requires API 34 (minSdk is 26)
  NewApi: java.time.LocalDate#EPOCH     requires API 34 (minSdk is 26)

Both are on the recalculation path. On any device below Android 14 — most of
the install base this app targets — that is a crash. Neither the unit tests nor
the API 36 emulator could see it; lint is the only thing that could.

Replaced with atZone().toLocalDate() and ofEpochDay(0), which are API 26.

Also cleared the lint warnings that were real: a redundant activity label, and
a round launcher icon declared but never referenced. The two that remain are
deliberate and now say so where the warning is read — targetSdk 36 is Play's
floor and raising it opts into untested runtime behaviour, and the -v26 mipmap
qualifier stays because removing it makes AAPT fail to resolve the icon at all.

./gradlew check now passes with 0 lint errors across all seven modules.
70 unit tests, all passing.

closes #7
2026-08-18 03:00:11 -05:00
null 96dd878ac5 chore: adopt the project template and add the Kotlin/Compose skeleton
Period was a bare directory holding one 2,527-line specification, with no git
repository, no tracker and no documentation convention. This is the adoption
from Projects/Template/START-HERE-New-Project.md, plus a project that compiles
so the hooks and future guards have something real to run against.

Documents. scaffold.sh created 19 paths, 0 skipped. The specification moved to
docs/planning/PRODUCT_PLAN.md unchanged in substance, with a status header; the
capitalised Docs/ is gone. Every scaffolded document was filled in for Period.
docs/OPERATIONS.md deleted — an offline app is not a deployed service.
DOC_TRUST_MAP.md written last, describing what is actually here, including what
this project deliberately does not have.

Code. Four Gradle modules. domain/cycle and domain/prediction are kotlin("jvm")
and cannot see the Android SDK, so the engine is testable without an emulator —
17 tests pass, 12 of them the acceptance cases from PRODUCT_PLAN.md §51.
BaselinePredictionEngine is a robust-median prototype and explicitly not the
product; it exists so Batch 02's replacement can be shown to be better rather
than merely different.

Versions verified against their official sources today rather than inherited
from the specification's own numbers, which that document asks for: Kotlin
2.4.10, AGP 9.3.1, Gradle 9.7.0, Compose BOM 2026.08.00, Room 2.8.4, Hilt
2.60.1. AGP 9 ships Kotlin built in, so org.jetbrains.kotlin.android is no
longer applied. compileSdk is 37 because current AndroidX requires it; targetSdk
stays 36, Play's floor from 2026-08-31, and the difference is deliberate.

Six scripts taken into scripts/; the rest declined and named in docs/TOOLS.md.
Three hooks in .githooks/, with pre-commit adapted to Gradle.

closes #1
closes #2
2026-08-18 02:16:47 -05:00