Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .claude/knowledge/gotchas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
how-to-apply: Free to use iOS 26 APIs. Don't add #available(iOS 17, *) checks. Don't fall back to ObservableObject for new view models. If you ever bump the project default, bump every per-target override too — mismatches break @testable import with "minimum deployment target" errors.

- id: secrets-are-gitignored
summary: Savely/Config.plist contains the OpenAI API key and must never be committed.
summary: Savely/Config.plist holds a local OpenAI API key and must never be committed.
why: Leaking it on a public repo means key rotation + potential abuse charges. (GoogleService-Info.plist used to be in this list; it died with the Firebase removal, 2026-08 — the historical copy in public git history is neutralized by deleting the Firebase project, not by scrubbing.)
how-to-apply: Before any commit, grep the staged diff for this path. If present, stop and tell the user.

Expand All @@ -28,10 +28,10 @@
why: The Xcode UI test template ships SavelyUITestsLaunchTests with XCTApplicationLaunchMetric which runs the app launch ~8 times measuring performance, taking ~5–10 min and flaking when one iteration exceeds the std-dev threshold. The template tests assert nothing meaningful — they only measure launch time, which is noisy on shared runners. Burning that many minutes for no signal is wasteful.
how-to-apply: Leave -skip-testing:SavelyUITests in .github/workflows/ci.yml's Test step until qa-tester writes real UI tests that exercise actual user paths. When real UI tests exist, drop the flag (or narrow it to skip only the template's launch-perf tests). Build step still compiles the bundle, so breaking changes to UI test code are still caught.

- id: ci-needs-placeholder-secrets
summary: CI generates a placeholder Config.plist before xcodebuild because it is a gitignored required build input.
why: Config.plist is listed as a required build input in project.pbxproj (Resources phase). On a fresh checkout (CI runners) it is absent and xcodebuild fails with "Build input file cannot be found" before compilation. The real key is not needed — CI never calls OpenAI. A placeholder with the right plist shape is sufficient. (GoogleService-Info.plist was also generated here until the Firebase removal, 2026-08.)
how-to-apply: The "Generate placeholder secrets" step in .github/workflows/ci.yml writes the file. Keep the placeholder's plist shape (OPENAI_API_KEY key) in sync with what OpenAIClient reads at runtime.
- id: config-plist-never-bundled
summary: Savely/Config.plist is NOT a Resources build input and must never become one again.
why: Anything in Resources ships inside the IPA and can be extracted, so a bundled key is a published key. 1.0 shipped it that way (key revoked 2026-08-19); 1.1 removed the build-phase entry, which also retired the CI placeholder steps in ci.yml and ci_post_clone.sh.
how-to-apply: If Xcode re-adds Config.plist to "Copy Bundle Resources" (e.g. dragging the file into the project with target membership checked), untick it. When Tips returns, serve the key from a proxy you control (docs/plans/drop-bundled-config-plist.md step 3) and relax the archive gate in ci_scripts/ci_post_clone.sh at the same time.

- id: force-unwrap-ratchet-active
summary: force_unwrapping is severity error in .swiftlint.yml — any new value! fails CI and the local pre-commit hook.
Expand Down
18 changes: 0 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,24 +68,6 @@ jobs:
# how to tighten this over time.
run: swiftlint lint --reporter github-actions-logging

- name: Generate placeholder secrets
# Config.plist (OpenAI) is gitignored locally, but the Xcode project
# lists it as a required build input. xcodebuild fails on a fresh
# checkout if it's absent. CI never calls OpenAI, so a placeholder
# with the right shape is sufficient. (GoogleService-Info.plist died
# with the Firebase removal — see docs/plans/remove-auth-firebase.md.)
run: |
cat > Savely/Config.plist <<'PLIST'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>OPENAI_API_KEY</key>
<string>ci-placeholder-not-a-real-key</string>
</dict>
</plist>
PLIST

- name: Build
run: |
set -o pipefail
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,6 @@ fastlane/Preview.html
fastlane/screenshots/
fastlane/test_output/
fastlane/README.md

# /brag launch-video renders (large, regenerable)
brag-output*/
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Savely/
├── Resources/ # Strings.swift, Localizable.xcstrings, Color+Warm.swift, UIConstants.swift
├── Assets.xcassets/ # Images + ColorPalette
├── Savely.entitlements # Sign in with Apple
├── Config.plist # OpenAI API key — GITIGNORED
├── Config.plist # local OpenAI key — GITIGNORED, not bundled

SavelyTests/ # XCTest unit tests (skeleton only today)
SavelyUITests/ # XCTest UI tests (skeleton only today)
Expand All @@ -92,7 +92,7 @@ These are invariants that future changes must respect. They were discovered duri

1. **Signing is automatic, team `ZHLD96SP29`.** Don't switch to manual signing. Don't edit signing build settings.
2. **No `.xcconfig` files exist** — all settings live in `project.pbxproj`. Touching pbxproj is risky; prefer Xcode UI edits and review the diff carefully.
3. **Secrets are gitignored:** `Savely/Config.plist` (OpenAI), anything matching `.env*`. Never commit these. Never paste their contents.
3. **Secrets are gitignored:** `Savely/Config.plist` (OpenAI), anything matching `.env*`. Never commit these. Never paste their contents. `Config.plist` is also never a Resources build input — a bundled key ships in the IPA (`gotchas.yaml#config-plist-never-bundled`).
4. **iOS 26.0 is the minimum deployment target** for the app target. Use modern APIs freely (`@Observable`, `NavigationStack`, Swift Testing, etc.).
5. **Only `Savely.xcscheme` is shared and tracked** in `Savely.xcodeproj/xcshareddata/xcschemes/`. Test commands must use `-scheme Savely`, never `-scheme SavelyTests`.
6. **Localization rule:** all user-facing strings go through `Resources/Strings.swift` constants and are registered in `Localizable.xcstrings`. No hardcoded literals in views.
Expand Down
Loading
Loading