mana-swift-event-sync sortierte lokal emittierte Events vor den bereits gesyncten (SwiftData/SQLite: NULL ist aufsteigend der kleinste Wert), womit ArticleSaved beim Replay zuletzt gewann. Deshalb blieben aus dem Share-Sheet gespeicherte Artikel dauerhaft auf ihrem Platzhalter stehen — 16 von 22 winfuture-Speicherungen in einer echten Datenbank, obwohl winfuture gar keine Cookie-Wand hat. Die App zieht das Paket über einen lokalen Pfad, der Fix ist also beim nächsten Build drin. Der Build selbst ist am 27.07. nicht entstanden: Xcodes Paketauflösung brach am Netz ab, und die Signierung braucht interaktive Freigabe. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
184 lines
10 KiB
Markdown
184 lines
10 KiB
Markdown
# pageta-native — Status
|
||
|
||
Letzter Stand: **2026-07-27**.
|
||
|
||
> **2026-07-27 — Sortier-Fehler im Event-Log behoben (Release ausstehend):**
|
||
> `mana-swift-event-sync` sortierte lokal emittierte Events (noch ohne
|
||
> `sequenceNumber`) VOR den bereits gesyncten — SwiftData sortiert über
|
||
> SQLite, und dort ist `NULL` aufsteigend der kleinste Wert. Der Replay
|
||
> wandte damit `ArticleSaved` zuletzt an und überschrieb jede spätere
|
||
> Änderung.
|
||
>
|
||
> **Folge in der Praxis:** aus dem Share-Sheet gespeicherte Artikel blieben
|
||
> dauerhaft auf ihrem Platzhalter stehen (Host als Titel, leerer Text),
|
||
> obwohl `enrichPendingArticles()` sauber `ArticleEnriched` nachgeschickt
|
||
> hatte. In einer echten Datenbank 16 von 22 winfuture-Speicherungen — und
|
||
> winfuture hat gar keine Cookie-Wand, die Extraktion wäre durchgelaufen.
|
||
>
|
||
> Behoben in `libs/mana-swift-event-sync` (`EventStorage.sortRank`), vier
|
||
> Tests, 42/42 grün. Die App zieht das Paket über einen **lokalen Pfad**
|
||
> (`project.yml` → `../../../libs/mana-swift-event-sync`), der Fix ist also
|
||
> beim nächsten Build automatisch drin — **kein Versions-Bump nötig**.
|
||
>
|
||
> ⚠️ **Offen: TestFlight-Build.** In der Sitzung vom 27.07. nicht erzeugt —
|
||
> Xcodes Paketauflösung brach beim Klonen von `swift-nio`/`mlx-swift-lm`
|
||
> am Netz ab (`RPC failed; curl 18`), und die Signierung braucht ohnehin
|
||
> interaktive Freigabe. Bis zum Release bleibt der Fehler auf den Geräten.
|
||
> Die Web-Reparatur („Neu extrahieren") holt betroffene Altlasten
|
||
> inzwischen nach — siehe `pageta/web/docs/EXTRAKTION.md`.
|
||
|
||
> **2026-05-29 — Release-Härtung + iOS-Build-Triage:**
|
||
> Build-Stand unter Xcode 26.3 verifiziert (sauberes DerivedData):
|
||
> - **macOS:** ✅ `BUILD SUCCEEDED`, reproduzierbar.
|
||
> - **iOS Device / Archive** (`generic/platform=iOS`): ✅ `BUILD
|
||
> SUCCEEDED`. Das Macro-Plugin `MLXHuggingFaceMacros` (transitiv via
|
||
> `ManaLLM` → `mlx-swift-lm`) wird hier korrekt fürs **Host-Target**
|
||
> (`arm64-apple-macos`) gebaut. **TestFlight ist nicht blockiert** —
|
||
> Archives bauen fürs Device.
|
||
> - **iOS Simulator:** ❌ „malformed response" beim Laden von
|
||
> `MLXHuggingFaceMacros` (`GemmaBackend.swift:127`). Ursache ist eine
|
||
> **simulator-spezifische** Arch-Kollision auf Apple Silicon: Host
|
||
> (arm64 macOS) und Simulator (arm64 iOS-Sim) haben dieselbe Arch,
|
||
> der Plugin-Loader greift die Simulator-Binary. Betrifft **nur den
|
||
> lokalen Sim-Dev-Loop**, nicht Device/Archive/Release. Workaround
|
||
> bis upstream-Fix: auf Device/„My Mac"-Destination entwickeln.
|
||
>
|
||
> Die ältere Behauptung „iOS-Sim grün, 38/38 Tests" (2026-05-25) galt
|
||
> für die damalige Toolchain; mit Xcode 26.3 ist der Sim-Pfad gebrochen.
|
||
> `mlx-swift-lm @ branch:main` bleibt konventionsgemäß (dokumentiert in
|
||
> `mana-swift-llm/CLAUDE.md`); kein Pin nötig, da Release-Pfad grün.
|
||
>
|
||
> **Fertig:** Die im 2026-05-25-Eintrag als offen notierten Write-Pfade
|
||
> im Markierungen-Tab (Note/Color/Delete) verschlucken Fehler nicht mehr
|
||
> — `MarkierungenTabView` zeigt sie jetzt als Alert (`writeError`),
|
||
> analog zu Lese-Liste/Reader.
|
||
|
||
> **2026-05-25 — Event-Sync auf geteilte Lib `ManaEventSync` migriert:**
|
||
> Die hand-gebaute Plumbing (Envelope/JSONValue/ULID/JWT/Storage/HTTP/
|
||
> Engine/Crypto/Vault, 9 Dateien ~900 LOC) ist raus; pageta konsumiert
|
||
> jetzt `mana-swift-event-sync` (`../mana-swift-event-sync`). Domäne
|
||
> (EventPayloads/States/Reducers/Coordinator) bleibt. Der Coordinator
|
||
> baut Events via `engine.makeEnvelope` — **kein `currentUserId()` mehr**,
|
||
> die Engine besitzt die Identität (Vorbereitung für Local-First ohne
|
||
> Login, E-4.5). Store-Name `pageta-event-sync` + App-Group unverändert
|
||
> → bestehende lokale Daten intakt. iOS-Sim-Build + 38/38 Tests grün.
|
||
> Erst-Adopter der Lib; wordeck folgt.
|
||
|
||
> **2026-05-25 — Markieren-Redesign (Books-Stil) + Fehler sichtbar:**
|
||
> Auswahl im Reader öffnet jetzt eine schwebende Farb-Palette direkt an
|
||
> der Auswahl (`HighlightSelectionPalette`) statt Edit-Menü → Bottom-
|
||
> Sheet; System-Edit-Menü unterdrückt, „Kopieren" lebt in der Palette.
|
||
> Ursache für „Markieren tut nichts": Schreibfehler (typisch *nicht
|
||
> eingeloggt* / stale `softFirst`-Session) wurden in `loadState`
|
||
> geschrieben, dessen UI aber nur bei `article == nil` rendert → still
|
||
> verschluckt. `addHighlight` zeigt den Fehler jetzt als Alert. 38/38
|
||
> Tests grün, iOS-Sim-Build clean. Nicht-eingeloggt-Fall führt jetzt
|
||
> über `ManaAuthGate.require` direkt ins Login-Sheet und holt die
|
||
> Markierung nach erfolgreichem Login automatisch nach (Alert bleibt
|
||
> Fallback für Rest-Fehler / stale `.signedIn`-Session). **Offen:**
|
||
> Markieren ganz ohne Login (Local-First/anon, eigener Umbau); System-
|
||
> Menü-Suppression + Palette-Platzierung am Gerät verifizieren; übrige
|
||
> Write-Pfade (Note/Color/Status) verschlucken Fehler noch genauso.
|
||
|
||
## Phase
|
||
|
||
**π-0..π-9 + π-11 ✅** — App baut iOS-Sim warning-frei, 38/38 Tests
|
||
grün (28 alt + 10 EventSync-Reducer). User-owned-CRUD läuft seit π-11
|
||
gegen `sync2.mana.how` (Event-Sourcing); HTTP-only bleiben Feed,
|
||
Extract-Preview und Widget-Snapshot. Nur π-10 (ASC) offen.
|
||
|
||
> **2026-05-20 — Phase π-11 (Event-Sync-Migration):** Reagiert auf
|
||
> pageta-api G-3 (retired articles-route, 2026-05-19), die alle
|
||
> user-owned-Article-Routen mit 410 antwortet. Native-App spricht
|
||
> jetzt direkt mit `sync2.mana.how`, mit lokaler SwiftData-Projection
|
||
> + Outbox + 60s-Polling. Surface von `PagetaAPI` bleibt identisch —
|
||
> UI unverändert. Pattern 1:1 aus nutriphi-native ν-14, reduziert auf
|
||
> Article + Highlight (Preferences-Aggregate ist offen, sobald
|
||
> Onboarding-UI dafür landet).
|
||
>
|
||
> **Design-Fix nebenbei:** Listentitel auf `.primary` umgestellt
|
||
> (statt `PagetaTheme.foreground` = dunkles Sepia). Im iOS-Dark-Mode
|
||
> sahen die Titel sonst muddy-orange aus, weil der paper-Theme-
|
||
> Foreground gegen schwarzen System-Background gerendert wurde.
|
||
>
|
||
> **Offen:** macOS-Build hängt am Mac-Provisioning-Profile, das die
|
||
> `Associated-Domains`-Capability nicht hat (Apple-Dev-Portal-TODO,
|
||
> nicht code-bezogen). π-10 (ASC + TestFlight) noch offen.
|
||
|
||
- **π-0**: paper-Theme, ManaAuthGate (Cross-App-SSO `ev.mana.session`),
|
||
AppIcon (Eselsohr-Page), AASA auf pageta.com.
|
||
- **π-1**: Feed-Tab via GET /api/v1/feed.
|
||
- **π-2**: Lese-Liste-Tab mit Status-SegmentedControl + Swipe-Actions.
|
||
- **π-3**: Reader-Detail (Plain-Text-Spike), Auto-`unread→reading`.
|
||
- **π-4**: Highlights Paragraph-Granularität via Tool-Endpoint + Tag-Sheet.
|
||
- **π-5**: Universal Links + pageta:// scheme → Sheet mit Reader.
|
||
7 URL-Router-Tests (Drift-Guard gegen pageta.mana.how).
|
||
- **π-6**: ShareExt (URL → App-Group-Queue → Launch-Flush an pageta-api).
|
||
Pattern aus herbatrium-native η-8.3.
|
||
|
||
## Phasen-Roadmap
|
||
|
||
| Phase | Status | Inhalt |
|
||
|---|---|---|
|
||
| π-0 | ✅ 2026-05-18 | Repo-Skelett, Login, Theme, Tab-Placeholder |
|
||
| π-1 | ✅ 2026-05-18 | Feed-Tab mit Pull-to-Refresh aus `GET /api/v1/feed` |
|
||
| π-2 | ✅ 2026-05-18 | Lese-Liste-Tab mit Status-Filter aus `GET /api/v1/articles` |
|
||
| π-3 | ✅ 2026-05-18 | Reader-Detail (Plain-Text-Spike + Toolbar) — Risiko-Spike entschieden zugunsten Plain-Text |
|
||
| π-4 | ✅ 2026-05-18 | Highlights (Paragraph-Granularität, 4 Farben) + Tag-Sheet — via Tool-Endpoints |
|
||
| π-5 | ✅ 2026-05-18 | Universal Links (pageta.com/article/:id) + pageta:// scheme → Sheet mit Reader |
|
||
| π-6 | ✅ 2026-05-18 | ShareExt (URL → App-Group-Queue → Launch-Flush) |
|
||
| π-7 | ✅ 2026-05-18 | WidgetKit Small/Medium/Large (App-Group-Snapshot, pageta:// Deep-Link) |
|
||
| π-8 | ✅ 2026-05-18 | Spotlight-Index für saved Articles + AppShortcuts (OpenFeed, SaveURL) |
|
||
| π-9 | ✅ 2026-05-18 | macOS-Adapt (NavigationSplitView + Sidebar + ⌘R Refresh + SceneStorage-Persistence) |
|
||
| π-10 | offen | ASC + TestFlight |
|
||
| π-11 | ✅ 2026-05-20 | Event-Sync-Migration auf `sync2.mana.how` (Article + Highlight Aggregate) — nutriphi-ν-14-Pattern |
|
||
|
||
**MVP-Cut**: π-0..π-4 (App + Login + Feed + Lese-Liste + Reader mit
|
||
Highlights). Phase 2: π-5..π-10.
|
||
|
||
## Vollständiger Plan
|
||
|
||
[`../mana/docs/playbooks/PAGETA_NATIVE_GREENFIELD.md`](../mana/docs/playbooks/PAGETA_NATIVE_GREENFIELD.md).
|
||
|
||
## Server-Pre-Conditions (alle ✅ vor π-0)
|
||
|
||
- ✅ AASA live auf `pageta.com/.well-known/apple-app-site-association`
|
||
- ✅ Widget-Snapshot-Endpoint `GET /api/v1/snapshot/widget` (JWT-gated)
|
||
- ✅ Primary-Switch zu pageta.com (Manifest base_url + PAGETA_PUBLIC_URL env)
|
||
|
||
## Apple-Dev-Portal-TODO
|
||
|
||
Till's manuelle Aktion vor erstem TestFlight-Build:
|
||
|
||
- [ ] Bundle-ID `ev.mana.pageta` registrieren (Team QP3GLU8PH3)
|
||
- [ ] **Bundle-ID `ev.mana.pageta.share`** (ShareExt, π-6 live im Code)
|
||
- [ ] **Bundle-ID `ev.mana.pageta.widget`** (Widget, π-7 live im Code)
|
||
- [ ] App-Group `group.ev.mana.pageta` für App **+ ShareExt + Widget** aktivieren
|
||
- [ ] **Keychain-Sharing-Group `ev.mana.session`** (Cross-App-SSO mit
|
||
anderen mana-Apps — Eintrag muss exakt matchen, sonst OSStatus
|
||
-34018 errSecMissingEntitlement beim ersten Token-Write)
|
||
- [ ] Capabilities: Associated Domains, App Groups, Keychain Sharing
|
||
- [ ] ASC-App-Eintrag (kommt mit π-10)
|
||
|
||
## Offene Punkte
|
||
|
||
- **π-3 Iteration 2** (deferred): Plain-Text-Render ist brauchbar,
|
||
aber lässt Headings/Bilder/Quotes/Code-Blocks/Links flach werden.
|
||
Wenn echte Content-Strukturen wichtig werden, Server-Markdown-
|
||
Convert (`turndown`) im pageta-api ergänzen + Native via
|
||
swift-markdown rendern.
|
||
- **π-4 Iteration 2** (deferred): Echte Text-Selection statt
|
||
Paragraph-Granularität. Brauchst UITextView-Bridge oder iOS-18+
|
||
Selection-Hook. Hat aber UX-Kosten (Long-Press-Auswahl muss
|
||
zuverlässig sein). Aktuell ist Tap-on-Paragraph der pragmatische
|
||
Cut.
|
||
- **Tag-Read-back fehlt server-seitig**: pageta-api hat keinen
|
||
`GET /api/v1/articles/:id/tags` und kein `tags`-Field im
|
||
Article-DTO. Native kann Tags hinzufügen, sieht sie aber nicht.
|
||
Web hat das gleiche Manko.
|
||
- **FeedItem-Tap** triggert noch keinen Save-Flow. Aktuell ist Feed
|
||
read-only. Save-from-Feed als Sub-Sprint (kleines Feature, kein
|
||
eigener π).
|
||
- **Reading-Progress-Persistierung** nicht implementiert. Scroll-
|
||
Offset wird nicht zum Server zurückgesynct. Status wird beim Open
|
||
auf `reading` gesetzt, aber kein granular Progress-Tracking.
|