Fix OpenSpec validation failures on medium-severity specs

- komoot-import: add SHALL to Credential storage requirement body
- local-dev-environment: add SHALL to Mobile app dev requirement body
- multi-day-routes: demote ### Note heading to plain paragraph to avoid validator treating it as a requirement

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-05-24 11:20:57 +02:00
parent bbb729ffdd
commit 38617ce0aa
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
3 changed files with 3 additions and 5 deletions

View file

@ -81,7 +81,7 @@ Each import run SHALL be tracked as a batch with status and statistics.
- **THEN** the batch shows: totalFound, importedCount, duplicateCount, and duration - **THEN** the batch shows: totalFound, importedCount, duplicateCount, and duration
### Requirement: Credential storage ### Requirement: Credential storage
Both connection modes store credentials in `connected_services` with `credential_kind = 'web-login'`. Public mode stores only the verified Komoot username; authenticated mode stores an encrypted email + password in the `credentials` JSONB blob. The Komoot provider uses a noop `CredentialAdapter` — it does not go through `ConnectedServiceManager`'s `withFreshCredentials` lifecycle (no token refresh needed for web-login credentials). Credential decryption for API calls happens inside the Komoot importer directly. Both connection modes SHALL store credentials in `connected_services` with `credential_kind = 'web-login'`. Public mode stores only the verified Komoot username; authenticated mode stores an encrypted email + password in the `credentials` JSONB blob. The Komoot provider uses a noop `CredentialAdapter` — it does not go through `ConnectedServiceManager`'s `withFreshCredentials` lifecycle (no token refresh needed for web-login credentials). Credential decryption for API calls happens inside the Komoot importer directly.
The four Komoot-specific routes (`/api/sync/komoot/connect`, `/api/sync/komoot/verify`, `/api/sync/komoot/import`, `/api/sync/komoot/import-status`) intentionally bypass the generic `/api/sync/connect/:provider` / `/api/sync/callback/:provider` framework — Komoot's bio-verification flow is too different from OAuth to fit the generic shape. The four Komoot-specific routes (`/api/sync/komoot/connect`, `/api/sync/komoot/verify`, `/api/sync/komoot/import`, `/api/sync/komoot/import-status`) intentionally bypass the generic `/api/sync/connect/:provider` / `/api/sync/callback/:provider` framework — Komoot's bio-verification flow is too different from OAuth to fit the generic shape.

View file

@ -81,7 +81,7 @@ The dev environment SHALL provide a command to tear down and recreate the local
- **THEN** all Docker volumes are removed and containers are recreated - **THEN** all Docker volumes are removed and containers are recreated
### Requirement: Mobile app dev (Expo) ### Requirement: Mobile app dev (Expo)
The `apps/mobile` React Native app (Expo) requires its own dev commands separate from the web stack. The project SHALL provide dedicated dev commands for the `apps/mobile` React Native app (Expo), separate from the web stack.
#### Scenario: iOS development #### Scenario: iOS development
- **WHEN** a developer runs `pnpm dev:ios` from `apps/mobile` - **WHEN** a developer runs `pnpm dev:ios` from `apps/mobile`

View file

@ -60,6 +60,4 @@ Day structure SHALL be preserved in GPX exports via waypoint type elements.
Note: the single-track export (without `splitByDays`) is the default. The per-day split is available as an option on the GPX generator and is the recommended format for multi-day exports to head units. Note: the single-track export (without `splitByDays`) is the default. The per-day split is available as an option on the GPX generator and is the recommended format for multi-day exports to head units.
### Note on overnight vs isDayBreak naming Note on overnight vs isDayBreak naming: The Yjs wire format stores the flag as `overnight: true` on the waypoint Y.Map entry. The TypeScript interface exposes it as `isDayBreak` (a comment in `waypoint-ymap.ts` documents `overnight` as the legacy wire name). Spec scenarios use `overnight` to refer to the wire-level concept; TypeScript code uses `isDayBreak`.
The Yjs wire format stores the flag as `overnight: true` on the waypoint Y.Map entry. The TypeScript interface exposes it as `isDayBreak` (a comment in `waypoint-ymap.ts` documents `overnight` as the legacy wire name). Spec scenarios use `overnight` to refer to the wire-level concept; TypeScript code uses `isDayBreak`.