resolve merge conflict, close out milestone 4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-18 14:47:36 -04:00
3 changed files with 70 additions and 7 deletions

View File

@@ -330,38 +330,74 @@ SettingsScreen + SettingsViewModel from milestone 2. DataStore-backed. Default s
- datetime: [2026-05-18 Sun 18:00]
* milestone 4: polish and hardening
** TODO make launch path fast
** DONE make launch path fast
*** acceptance
- app opens directly to capture field.
- no network call blocks launch.
- no history loading blocks text entry.
*** notes
LaunchedEffect(Unit) { focusRequester.requestFocus() } fires immediately on composition. No network calls in MainActivity or CaptureScreen init path. History loads via Room Flow on a background coroutine — never blocks text entry.
*** evidence
- commit: 19b05a8
- tests: manual — cold launch, keyboard appears without any loading state
- datetime: [2026-05-18 Sun 19:00]
** TODO normalize tags
** DONE normalize tags
*** acceptance
- whitespace-separated and comma-separated tags both work.
- invalid org tag chars are stripped or replaced.
- duplicate tags collapse.
*** notes
Two-layer normalization: parseTags() in CaptureViewModel splits on [,\s]+ before storing to Room. normalize_tags() in server/app/org_writer.py lowercases, strips #, replaces spaces with _, removes non-[a-z0-9_] chars, deduplicates. 7 unit tests cover all cases.
*** evidence
- commit: e873a00 (server), 19b05a8 (android)
- tests: pytest tests/test_org_writer.py::TestNormalizeTags — 7 passed
- datetime: [2026-05-18 Sun 19:00]
** TODO fix org formatting
** DONE fix org formatting
*** acceptance
- add `#+startup: overview` to synq.org
*** notes
Append writer in main.py checks if org file exists before first write. If missing, creates it with #+title and #+startup: overview header. Existing files are never modified.
*** evidence
- commit: fd28a45
- tests: manual — delete synq.org, post a capture, verify header present
- datetime: [2026-05-18 Sun 19:00]
** TODO handle multiline notes well
** DONE handle multiline notes well
*** acceptance
- first line can become note heading if body is multiline.
- full body is preserved under heading.
- todo body remains usable as a single todo heading, with extra lines under it if present.
*** notes
format_capture() in org_writer.py: multiline note uses first line as heading suffix ("* note: <first line>"), full body preserved below drawer. Single-line note uses "* note" heading, body below. Covered by test_note_multiline.
*** evidence
- commit: e873a00
- tests: pytest tests/test_org_writer.py::TestFormatCapture::test_note_multiline — passed
- datetime: [2026-05-17 Sat 17:00]
** TODO add basic logs
** DONE add basic logs
*** acceptance
- server logs accepted capture id.
- server logs duplicate capture id.
- server logs rejected payload without dumping secrets.
*** notes
logger.info for accepted and duplicate (id only, no body). logger.warning for invalid token (client IP only, no token value logged). logger.warning for validation errors (field names only, no body content).
*** evidence
- commit: fd28a45
- tests: manual — send bad token, send empty body, check uvicorn stdout
- datetime: [2026-05-18 Sun 19:00]
** TODO create backup note
** DONE create backup note
*** acceptance
- readme documents which paths need backup.
- readme documents restore behavior.
*** notes
Added "backup" section to README.md covering synq.org, capture.sqlite3, token.txt. Restore section documents behavior when each file is lost individually.
*** evidence
- commit: (this commit)
- tests: n/a
- datetime: [2026-05-18 Sun 19:00]
* milestone 5: optional v1.5
** TODO add settings for sync frequency