Merge remote-tracking branch 'origin/237958b2c8722ce0f87cf139d9e17988ea4d075c' into 237958b2c8

This commit is contained in:
alex phone S25
2026-05-28 18:34:57 +06:00
4 changed files with 126 additions and 9 deletions
+21 -2
View File
@@ -13,7 +13,7 @@ tags:
- psychology
- skip-tools
created: '2026-05-17'
updated: '2026-05-25'
updated: '2026-05-28'
related:
- "[[personal/projects/psychologist-app/overview]]"
- "[[personal/projects/psychologist-app/dev-setup]]"
@@ -25,7 +25,7 @@ related:
- Активная кодовая база: `~/Developer/reflect-skip/`
- Android: публикуется на `https://reflect.qentra.top` (F-Droid)
- iOS: собирается через `Project.xcworkspace``Darwin/ReflectApp.xcodeproj`
- Текущая версия: v0.0.25
- Текущая версия: v0.0.92 (Android APK), v0.0.25 (iOS)
## Структура проекта
@@ -52,6 +52,25 @@ related:
- **AnalystBot** — задаёт 2-3 глубоких вопроса по профилю + контексту сессии
- **SessionManager** — управляет историей сессий
## Исправления (v0.0.92, 28 мая 2026) — Android vault validation
### Веха: Android onboarding работает
✅ Алерт валидации vault отображается корректно
✅ Кнопки появились после выбора папки
✅ Дошли до экрана "Доброе утро"
### Fix — @AppStorage вместо @State для UI-обновлений на Android
**Проблема:** `@State var folderPickerError: String?` и `@State var vaultFound: Int?` не триггерили Compose recompose в SkipFuse bridge.
**Симптом:** алерт не появлялся, кнопки не обновлялись, хотя логика SAF выполнялась.
**Исправление:** заменили на `@AppStorage("_vaultErr")` и `@AppStorage("_vaultFound")` — идут через SharedPreferences → всегда триггерят Compose recompose.
**Файл:** `Sources/naisei/Views/OnboardingView.swift`
### Открытые проблемы (v0.0.92)
- ❌ На главном экране "0 сессий", "0 дней"
- ❌ Профиль и Инсайты пустые
- ❌ Агент при начале сессии говорит "нет данных" (не видит vault)
- **Гипотеза:** vault URI сохраняется, но ProfileManager/SessionManager читают данные не через SAF URI, а по прямому пути — на Android без SAF доступа путь недоступен
## Исправления (v0.0.25, май 2026)
### Fix 1 — дублирование нарратора
@@ -0,0 +1,45 @@
# reflect-skip Android SAF Debug Log
## Root Cause Found (2026-05-28)
### Problem: #if SKIP blocks dead in Skip Fuse mode
The project uses SkipFuse (not transpile-mode Skip). In Fuse mode:
- `#if SKIP` is NOT defined — only `#if SKIP_BRIDGE` is active
- All SAF-based code in ProfileManager used `#if SKIP` guards
- Fallback iOS FileManager code ran instead → empty profile, 0 sessions, agent said "no data"
This affected ALL vault read/write operations:
- `loadProfile()` → returned ""
- `sessionCount` → returned 0
- `loadRecentSessions()` → returned ""
- `loadSessionDocuments()` (BM25 search) → returned []
- `appendSession()` / `updateProfile()` / `addInsight()` → wrote nothing
### Secondary Bug: HomeViewModel dead regex
`HomeViewModel.loadStats()` searched for `"Сессий проведено: (\d+)"` in profile.md.
This string is NEVER written anywhere in the codebase.
Fixed to use `ProfileManager.shared.sessionCount` (actual file count).
## Fix Applied
`Sources/ReflectApp/Services/ProfileManager.swift`:
- Added private SAF bridge helpers (`saf_read`, `saf_write`, `saf_list`, `saf_exists`, `saf_mkdirs`) using `AnyDynamicObject(forStaticsOfClassName: "reflect.app.AndroidAppMain")`
- Changed all `#if SKIP``#if SKIP_BRIDGE` throughout the file
- Added `#if SKIP_BRIDGE` blocks to methods that had no SAF guard: `appendToProfile`, `incrementSessionCount`, `loadSessionDocuments`, `updateSessionIndex`, `getSessionIndex`
`Sources/ReflectApp/ViewModels/HomeViewModel.swift`:
- Replaced dead regex with `ProfileManager.shared.sessionCount`
## Milestone History
| Date | Version | Milestone |
|------|---------|-----------|
| 2026-05-28 | 0.0.91 | Alert shows files found, buttons appear, HomeView loads |
| 2026-05-28 | 0.0.93 | SAF reads work in Fuse mode → sessions/profile visible |
## Pattern for future Skip Fuse code
In Skip Fuse projects, ALWAYS use `#if SKIP_BRIDGE` (not `#if SKIP`) for any Android-native calls.
Use `AnyDynamicObject(forStaticsOfClassName: "your.package.ClassName")` to call Kotlin companion object methods.