docs: bring the docs in line with what shipped

STORAGE-AND-SYNC.md asked for a follow-up pass on ARCHITECTURE.md §7 and the
ProviderResolver KDoc, which still defined Posture B as "bundle OpenTasks and
find org.dmfs.tasks first" — the plan that was withdrawn as a dead end. That pass,
plus the status the doc left open.

ARCHITECTURE.md now describes the app as built: two modules, the storage-mode
table with the permission each needs, the autoMode rule and why it keys on
holding an external provider's permission, the two-not-three mode vocabulary, and
a manifest section that says what :provider contributes and what is deliberately
absent (GET_ACCOUNTS, INTERNET). §7 records squatting the dmfs authority as a
dead end rather than a road not yet taken, so it doesn't get re-proposed.

ROADMAP.md turns "Posture B, later" into what actually landed and lists what
didn't: the frontend surfaces, the DAVx5 issue, the sync adapter, and device
verification. Two open decisions resolved and struck through — the authority
choice, and recurrence-aware editing, which fix/provider-interaction-review made
stale.

STORAGE-AND-SYNC.md gets per-step status. Open question 3 ("does it work with no
account?") is answered, with the caveat that the test proving it is Robolectric
and skips on ARM64 — answered by construction, not yet on a device.

PLAN.md gets a banner. It's the original design document and still holds the
reasoning behind the layering, but two of its premises are overturned and it
should not be read as current.

README.md was telling users they need a tasks provider installed. They don't, and
that's the headline feature: a table of where tasks can live, that our provider
coexists with OpenTasks rather than replacing it, and that everything exports as
standard .ics.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-02 21:32:17 +02:00
parent c5041d3f29
commit 98ed339346
5 changed files with 301 additions and 120 deletions

View File

@@ -10,16 +10,18 @@ Status legend: ✅ done · 🚧 in progress · ⬜ not started
## Current state (one line)
The full non-visual stack ("backoffice") over the OpenTasks `TaskContract`
provider is **done and unit-tested**, and the Material 3 Expressive UI is built
through **M5**: lists → task list (swipe gestures, inline add, smart-list section
headers) → detail / edit with full CRUD, date-time pickers, priority,
percent-complete, conflict-safe saves, per-task reminders, and subtask
create + reparent — plus a one-time reminder onboarding step and a Settings
screen (theme, dynamic colour, due-reminder master toggle + default offset +
exact-alarm status, default list, and the add-a-subtask-row opt-out). Remaining
work is M6 (Glance widget, translations, F-Droid release; the Settings screen
landed early with M5 and still needs a language entry).
Agendula now **carries its own task store**: the `:provider` module ships the
vendored dmfs provider under our authority, so the app is complete and local-first
with nothing else installed, and an external provider (OpenTasks / tasks.org) is a
user choice rather than a requirement. The non-visual stack over `TaskContract` is
done and unit-tested, export to iCalendar has landed, and the Material 3
Expressive UI is built through **M5**: lists → task list (swipe gestures, inline
add, smart-list section headers) → detail / edit with full CRUD, date-time
pickers, priority, percent-complete, conflict-safe saves, per-task reminders, and
subtask create + reparent — plus a one-time reminder onboarding step and a
Settings screen. Remaining work is the **frontend surfaces for what just landed**
(a storage-mode picker, an export screen), then M6 (Glance widget, translations,
F-Droid release) and the sync adapter.
---
@@ -128,11 +130,33 @@ The engine exists (M1: `ReminderScheduler` + boot / provider-change re-sync,
- ⬜ Translations — only `res/values/` (English); no `values-XX`.
- ⬜ Finalize F-Droid metadata, confirm CI release flow.
### Posture B (separate track, later)
Add a `:provider` module bundling the Apache-2.0 `opentasks-provider`;
`ProviderResolver` defaults to our own `org.dmfs.tasks`; add sync-adapter
permissions; ship self-contained. UI / repository / domain untouched — see
[`ARCHITECTURE.md`](ARCHITECTURE.md) §7.
### Posture B — our own task store
Agendula stopped depending on a provider app being installed. Direction and
reasoning in [`STORAGE-AND-SYNC.md`](STORAGE-AND-SYNC.md); note it **redefined**
what Posture B means (our own authority, coexisting with everything — *not*
squatting `org.dmfs.tasks`, which is a dead end).
-`fix/provider-interaction-review` merged (step 1).
-`:provider` — the Apache-2.0 dmfs provider 1.4.2 (DB 23) vendored in-tree
under `de.jeanlucmakiola.agendula.tasks` and our own permission namespace.
`GET_ACCOUNTS` dropped, with the account-cleanup path reworked so it can only
prune account types we authenticate ourselves — the deletion is unsafe without
that rework. Modernized to minSdk 29 / targetSdk 36 / Java 17.
[`provider/PROVENANCE.md`](../provider/PROVENANCE.md) records every deviation,
each also marked `AGENDULA CHANGE` at the site. Upstream's 51 JVM tests pass.
- ✅ Storage modes + the permission-gate bypass — `ProviderStatus.NEEDS_PERMISSION`
can no longer fire in Local mode, and an upgrading Posture A user stays on the
provider that holds their data (`ProviderResolver.autoMode`).
- ✅ Export to iCalendar (step 3) — a v1 feature now that Local-mode data lives
only in our app's private storage. One `.ics` per list, to a folder or a zip,
via SAF. Backend only.
-**Frontend surfaces for the above** — a storage-mode picker in Settings and
an export screen. The backend is done and unused until these exist.
- ⬜ File the DAVx5 issue (step 4) — non-blocking, cheap, serves F-Droid users.
- ⬜ Sync adapter (step 5) — the 1.x arc. Design discussion still open: protocol
coverage, account model, conflict resolution, and `ical4android`'s licence
against our MIT.
- ⬜ Verify on a device: the local path with no account, and the vendored
provider's timezone-change behaviour (change 3 in `PROVENANCE.md`).
---
@@ -145,11 +169,20 @@ These carry over from [`PLAN.md`](PLAN.md) §9; resolved ones are struck through
`org.tasks.opentasks` + `org.tasks.permission.*`.
3. **jtx Board** — support its richer contract later, or stay OpenTasks-only?
(Not in the candidate list today.)
4. **Posture B authority choice** — bundling `org.dmfs.tasks` makes Agendula a
*replacement* for OpenTasks (one authority owner per device). Intended, but a
conscious choice.
5. **Recurring tasks** — read as occurrences today (`isRecurring` flag exists);
recurrence-aware editing is out of scope for v1.
4. ~~**Posture B authority choice**~~ resolved: **our own**
`de.jeanlucmakiola.agendula.tasks`. Squatting `org.dmfs.tasks` is a dead end,
not merely a trade-off — two apps cannot declare the same authority or
permission name, so anyone with OpenTasks installed could not have installed
Agendula at all.
5. ~~**Recurring tasks** — recurrence-aware editing out of scope for v1~~ stale:
`fix/provider-interaction-review` routes edits to a recurring task through the
instances URI, so the provider forks an override instead of re-anchoring the
series.
6. **Resolver ordering / mode-selection UX**`autoMode()` picks a sane default
today (see [`ARCHITECTURE.md`](ARCHITECTURE.md) §4.1); the Settings override it
assumes is not built yet.
7. **Sync protocol coverage**, account model, conflict resolution — the next
design discussion.
---