release: CheatSheet 1.2 (Spanish, analytics, iOS 26 baseline, new screenshots) - #6
Merged
Merged
Conversation
Raise the deployment floor to iOS 26.0 / macOS 26.0, pin the test runtime to iOS 26.5 or newer, and make both contracts enforceable rather than assumed. Deployment floor: - project.yml declares iOS 26.0 and macOS 26.0, and drops the duplicate MACOSX_DEPLOYMENT_TARGET from settings.base so options.deploymentTarget is the single source of truth for the macOS floor. - Every availability gate is now unconditionally true, so the Liquid Glass paths in LiquidGlassGroup.swift and ViewModifiers.swift call the API directly and the macOS/iOS arms collapse into one. No #available or @available checks remain in the codebase. - 26.0 rather than a point release: nothing in the app needs a 26.x point API, so a higher floor would delete the same code and support fewer devices. SDK contract: - Scripts/verify-build-sdk.sh asserts the active toolchain's SDK major matches the branch contract (26), so a machine carrying an Xcode beta cannot silently produce a beta-SDK submission build. CI hard-fails; Scripts/verify-macos.sh warns, since developing on a beta is fine. Test runtime: - Scripts/resolve-ios-simulator.sh takes a minimum runtime (26.5 by default, CHEATSHEET_MIN_IOS_RUNTIME to override) and fails with a per-runtime breakdown rather than falling back below the floor. A green suite that ran on an unsupported runtime certifies nothing. - It matches device family on deviceTypeIdentifier instead of the display name; renamed simulators were being skipped entirely. Ranking now prefers stock-named devices so the pick is reproducible. Enforcement and CI: - Scripts/verify-project-config.sh asserts the deployment floors, so a regression fails CI instead of shipping. - CI moves to the macos-26 runner: a macOS 26 app cannot run on a macOS 15 host, and macos-26 also carries an SDK and simulator runtime satisfying both floors. Xcode selection prefers a versioned Xcode 26 bundle but defers to the SDK check as the real gate, since a bundle name cannot guarantee an SDK version. Docs/os-support-policy.md records the policy, the branching model for iOS 27 adoption, and the measured iOS 27 readiness result. Verified locally: 55 tests in 5 suites pass on both the iOS simulator and macOS, iOS Release builds clean, 0 warnings. The iOS 26 SDK itself is not installed on this machine, so CI remains the authority for the shipping SDK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
simctl keeps listing the iOS 27.0 beta runtime as available after switching back to the release Xcode, so "newest wins" sent shipping test runs onto the beta OS. Under Xcode 26.6 the resolver picked an iOS 27.0 iPhone rather than the 26.5 one. Exclude runtimes whose major exceeds the active simulator SDK. The toolchain now sets the ceiling, so the iOS 27 readiness branch needs no special case: selecting Xcode 27 raises it automatically. Major-level rather than exact, so a 26.6 runtime under a 26.5 SDK stays usable. Verified under Xcode 26.6 (SDK 26.5): the resolver returns the iOS 26.5 iPhone 17 Pro (9C915472), and the diagnostic marks 27.0 runtimes as newer than the active SDK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
parsedChecklistLine stripped heading markup with trimmingCharacters(in: CharacterSet(charactersIn: "# ")), which trims BOTH ends. Any heading ending in "#" silently lost it: "# C#" rendered as "C" "# F#" rendered as "F" "# C# vs F#" rendered as "C# vs F" DisplayLine lives in Shared/Sources, so this hit the editor and the widget on both platforms -- and "C#"/"F#" headings are ordinary content in a developer cheat sheet, which is what this app is for. Strip only the leading hashes instead, then trim whitespace. Adds two regression tests. Verified: 57 tests in 5 suites pass on macOS (was 55). The fixed parser was also compiled standalone against the four pre-existing heading/task/plain cases to confirm nothing outside the bug changed behaviour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The workflow duplicated its setup four times, ran only on main, kept no diagnostics, and never verified the shipped Mac binary was universal. Structure: - New composite action .github/actions/setup replaces the Xcode-select, SDK-assert, XcodeGen and generate steps duplicated across both jobs. - A cheap `checks` job runs first. It asserts the deployment floor, App Group wiring and privacy-manifest reasons -- none of which any build catches, since every xcodebuild here passes CODE_SIGNING_ALLOWED=NO -- so a bad config fails in seconds instead of after twelve minutes of simulator work. - iOS and macOS both gate on it and run in parallel. Coverage: - Universal macOS Release build with an explicit lipo assertion on both the arm64 and x86_64 slices. Nothing previously proved the shipped Mac app carried both, and macOS still ships to Intel. Only the x86_64 *test* run needs Rosetta, which the arm64 runner does not document, so that half stays in Scripts/verify-macos.sh for local use. - iOS unit tests run once rather than on every matrix leg; they are pure logic and device-independent. - The UI step drops -only-testing. The UI target globs its whole source directory, so naming classes there silently skipped any newly added class. Operations: - concurrency cancels superseded runs, so a new push stops burning the macOS runners the previous one held. - permissions: contents: read. - Push now also builds `develop`, which was previously merged unverified. - Result bundles are written and uploaded on failure. UI tests attach screenshots with .keepAlways; those previously died with the runner and every failure had to be reproduced blind. iPad is intentionally not a matrix leg yet: the UI suite here has no iPad handling, so the leg would fail. The rationale and the one-word change to enable it are recorded inline. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Localize every user-visible string in CheatSheet and its WidgetKit extension into neutral international Spanish (es), following Apple's String Catalog approach: - Add CheatSheetApp/Resources/Localizable.xcstrings and CheatSheetWidgets/Resources/Localizable.xcstrings with English and Spanish translations for every UI string, including onboarding, the editor, sidebar, trash, settings, the macOS menu bar extra, and the widget's empty and populated states. - Fix several call sites that silently bypassed SwiftUI's automatic string-catalog lookup because a String value sat between the literal and Text()/Label() (color and font display names, the trash countdown, storage error descriptions, the widget empty-state title, onboarding step rows, the persistence status banner, and the default/fallback note title and starter notes), switching them to String(localized:) with stable keys or LocalizedStringKey so Spanish translations actually apply. - Localize the first-run starter notes and default new-note title so a Spanish-speaking user's first launch isn't in English. - Add Scripts/verify-localization.sh, wired into CI, to check both catalogs for missing translations and mismatched %@/%lld placeholders between languages. - Add LocalizationTests (Swift Testing) covering the localized call sites' fallback behavior, and CheatSheetiOSSpanishLocaleUITests, a UI smoke suite that launches under -AppleLanguages (es-ES) to confirm the Spanish catalog actually renders in onboarding, the seeded starter note, and the empty Trash state. - Document the localization setup in README.md and add Docs/app-store-localization-es.md with proposed Spanish App Store Connect metadata. Existing English strings, accessibility identifiers, and default values are unchanged, so the existing English-locale test suite is unaffected; XcodeGen already picked up the new catalogs and added `es` to the project's known regions automatically.
Adds -cheatsheet-seed-screenshot-demo, gated behind the existing UI-testing in-memory store path, so App Store screenshot captures are reproducible without manual tapping and never touch a real device's notes. Demo content is 8 generic, accurate developer-reference notes (git/docker/vim/HTTP facts), same spirit as the existing "Git Flow" starter note. Also adds AppStoreScreenshots/ planning docs (feature evidence, visual DNA, message map) grounding the screenshot brief in actual app source rather than invented UI. Verified: 64/64 unit tests pass; manually launched the built app with the new flag and visually confirmed all 8 notes render correctly with distinct colors and the pin/widget flag on Git Rescue. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
16 evidence-verified concepts (iPhone 6, iPad 3+1 reused, Mac 2+1 reused) after generation, scoring, and one targeted retry of a lens that failed to a transient rate limit. Two claims from the unreviewed cross-platform-depth lens (the Cmd-N shortcut and the 5-note Recent Notes cap on Mac) were independently re-verified against source rather than trusted as-is. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
compose_screenshot.py implements the approved Brand Gradient style: full-bleed gradient canvas, eyebrow+headline caption in dedicated space above the device (never overlapping real UI, per user feedback on the first pass), real device bezel cropped at the bottom edge, real SF system font. Verified output is exactly 1320x2868 with no alpha channel. style-direction.md records the two-pass approval (backdrop choice, then a caption-layout correction against real reference examples) so this isn't re-litigated in later work. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Found during a review pass: the --device parameter was accepted and plumbed through to compose(), but nothing in the function body branched on it — every device silently got the iPhone treatment, including a Dynamic Island cutout that real iPads don't have. - iPhone keeps the pill-shaped island; iPad gets a small circular camera dot instead, and a smaller corner radius (both verified against reference photos) - 'mac' now fails fast (invalid --device choice) instead of quietly rendering an iPhone-style bezel — Mac has no frame design yet, see style-direction.md - Re-verified: iPhone output unchanged, iPad output now correct, mac correctly rejected. ~2.5s per image, fine for 16+ concepts. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The concept-matrix.csv has always had 15 rows (10 iphone + 3 ipad + 2 mac) - "16" was a stray miscount in the shortlist.md summary line and style-direction.md's cross-reference, caught during a review pass (verified by parsing the actual CSV with csv.DictReader). Per-device breakdowns were already correct; only the total was wrong. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
testQASweep_iPad (added in an earlier session as an iPad-only interactive QA walkthrough) was reused against iPhone's compact layout as-is and hit two real cross-device gaps, both root-caused against the live accessibility hierarchy rather than guessed at: - The pin invariant check queries the sidebar list's "Pinned" image, which only stays on screen on iPad's NavigationSplitView. iPhone's compact NavigationStack pushes the editor over the list, so the list briefly isn't part of the accessible hierarchy at all. Added returnToListIfPushed(in:), a no-op on iPad/Mac, which pops back via the nav-bar back button first on iPhone. - Clearing the search field's text doesn't end its active/focused session; .searchable() keeps the Cancel/Close button up and hides the rest of the toolbar (New Note, Show Trash, ...) until that session is dismissed. Added dismissSearchIfActive(in:) to tap Close after search. Renamed testQASweep_iPad -> testQASweep now that it's genuinely cross-device. Verified 0 failures on both a booted iPhone 17 Pro and iPad Pro 11-inch (iOS 27 simulators), screenshots spot-checked visually. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two tests failed on iOS 26.5 having only ever run on iOS 27.0 (the simulator resolver used to prefer the newest runtime). Both were environment-sensitive rather than product failures -- verified by running them against pre-rebase code on the same simulator, where they fail identically. Spanish empty-Trash test: it asserts a translated *string*, but reached Trash by driving the toolbar. That item lives in the secondary-action group, which iOS collapses into a system "More" overflow at compact widths -- and a collapsed item becomes a plain menu row that no longer resolves by accessibility identifier, so the fallback could never succeed. Adds a -cheatsheet-show-trash launch argument (gated on UI testing, alongside the existing onboarding hooks) so the test lands in Trash directly, and deletes the chrome-driving helper. English suite: it asserts rendered English text in roughly ten places but pinned no locale, passing only because the runner happens to be English. Pins -AppleLanguages/-AppleLocale like the Spanish suite already does. Search checkpoint: typed into the search field without waiting for first responder, which on a loaded machine surfaces as "Neither element nor any descendant has keyboard focus". Adds a focusForTyping helper that waits for the keyboard, and re-focuses before the clearing pass, since the screenshot between the two steps is long enough for .searchable to drop focus. CI: drops the -only-testing allow-list. The UI target globs the whole directory, so a new test class joined the target but not the list and would silently never run. Fails closed now. Verified: 66 tests in 6 suites pass on macOS. The UI changes need a simulator, which this machine cannot currently boot (process limit), so CI verifies them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The app ships iPad (TARGETED_DEVICE_FAMILY "1,2") and the UI it presents there is structurally different: a NavigationSplitView with a sidebar rather than a compact NavigationStack with a navigationBarDrawer search field. The UI suite branches on the idiom, but only the iPhone half had ever run -- CI resolved a single iPhone simulator for every iOS step, so the iPad paths were dead code in practice. Adds ipad to the existing matrix. fail-fast is already false, so one device failing still reports the other. Unit tests stay pinned to the iphone leg; they are pure logic and device-independent. No other change was needed: Scripts/resolve-ios-simulator.sh already takes a device family, and the macos-26 image carries iPad models on the iOS 26.5 runtime the resolver selects. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adding the ipad leg to CI (previous commit) failed 3 of 12 UI tests. All three were the suite's helpers assuming an iPhone-shaped NavigationStack; NavigationSplitView needed different queries, not different behavior. Root-caused each by dumping the real accessibility tree rather than guessing: - revealSearchField: .searchable(placement: .sidebar) puts the field above the sidebar's first row, off-screen above the viewport. A full-screen swipeDown() (the iPhone path) hits the detail pane and scrolls nothing. Falls back to swiping the "Sidebar" collection view directly. - returnToList: with two navigation bars on screen (sidebar + detail pane), navigationBars.buttons.firstMatch resolved to the DETAIL pane's first button -- "New Note" -- so this was silently creating a note instead of navigating. iPad has nothing to pop; the list is always visible. Guarded on a new isSplitViewLayout(in:) check. - Two membership/deletion assertions: a note's title renders in both the sidebar row and the detail pane on iPad, so app.staticTexts[title] is ambiguous, and a stale detail pane can defeat a "no longer in the list" check. Added noteList(in:) to scope those queries to the actual list. - Permanent-delete confirmation: both the detail pane and the confirmation dialog have a "Delete Now" button. Picking the last app-wide match assumed the dialog sorts after the pane, which does not hold on iPad, where the confirmation is a popover -- the pane's own button was tapped, the dialog was never confirmed, and the note silently survived. Added confirmPermanentDelete(in:), scoped to the sheet/alert container. Verified: 12/12 pass on iPad, 12/12 on iPhone -- including on a fresh, disposable simulator, to rule out interference from other sessions sharing this machine's simulators. Zero syntax errors from a standalone parse of the changed file. Also removed four identical, untracked duplicate files (iCloud sync artifacts: Localizable 2.xcstrings, ScreenshotDemoContent 2.swift, LocalizationTests 2.swift, verify-localization 2.sh) that broke local compilation with "invalid redeclaration" -- unrelated to this branch, but blocked reproducing the CI failure locally. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Version ------- 1.1 (13) -> 1.2 (14). The released v1.1.0 shipped build 13 on 2026-06-10, so resubmitting at that build number would be rejected as a duplicate. Minor rather than patch: this line carries a user-visible bug fix (headings ending in "#", e.g. "# C#", rendered with the hash eaten in both the editor and the widget), full Spanish localization, and an iOS 26 / macOS 26 baseline. CI -- Excludes testQASweep from the blocking UI gate via -skip-testing, which fails closed -- unlike -only-testing, a newly added test class still runs. That test is a 164-line, 13-checkpoint, two-launch monolith whose own header describes it as a manual verification pass; it exists to capture App Store screenshots. As a gate it flaked at four different assertions across consecutive runs (lines 328, 359, 439, 451) while passing on the identical commit on another branch, including the run that turned develop red after the iPad leg merged. Every checkpoint it asserts is already covered by the focused tests beside it, so skipping it loses no coverage. The comment records how to run it on demand for screenshot capture. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nine store-ready images (6 iPhone at 1320x2868, 3 iPad at 2064x2752) in AppStoreScreenshots/final/, plus the capture path that reproduces them. Preview line no longer repeats the title ---------------------------------------- Rows rendered their title twice -- "Git Rescue / Git Rescue" -- because notePreviewLine returns the first non-empty parsed line and both shipped starter notes open with "# <their own title>". Every first-run user saw it, and it read as placeholder data in the hero screenshot. notePreviewLine now takes an optional title and skips a leading heading that exactly matches it; CheatSheetNote.previewLine passes it. Only an exact match is skipped, so "# Before you push" under a note titled "Git Rescue" still shows. The hero slide now reads "Git Rescue / git switch -c fix/name", "Docker Cleanup / docker ps -a" -- every row demonstrating the product. Fixed in the app rather than the demo content on purpose: fixing only the seed would have made the listing show something users never see. MarketingScreenshotTests ------------------------ A capture path separate from testQASweep. That sweep creates a throwaway "QA Sweep Note" with placeholder body text, so from its third checkpoint on every capture shows test data -- one shot was a half-keyboard view of "- [x] Done task line# New Cheat Sheet". Apple treats placeholder content in a listing as grounds for rejection. The new tests only ever photograph seeded ScreenshotDemoContent, and archive a real note so the Trash shot carries content instead of an empty state. They passed 3/3 on both iPhone and iPad first run, where the sweep flaked. CI skips them: they are a capture tool, not a gate. Captions -------- Apple began OCR-indexing caption text in June 2025, making captions a Tier 1 ranking signal that -- unlike title/subtitle -- should reinforce core keywords. Each headline is 4-6 words, action-led where natural, owning one keyword theme, white on the dark brand gradient for OCR contrast. Verified: 69 tests in 6 suites pass; all nine images are exact upload-slot sizes with no alpha channel; status bar pinned to 9:41 per Apple convention. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A full local suite run surfaced two iPhone failures that were not product
bugs:
testTrashRestoreAndPermanentDeleteFlow -- Failed to tap "Select All"
MenuItem: No matches found
testEditAndSearchFlow -- failed to scroll to visible (by AX action)
Button 'Return', kAXErrorCannotComplete
Both tap system chrome the moment they ask for it. The edit menu and the
keyboard appear on their own schedule, later on a loaded machine, so these
fail under load and pass on an idle one -- the same class of false signal
that made testQASweep useless as a gate.
The suite already contained the correct pattern: the QA sweep's own Select All
waits for the menu first. Two of the three call sites did not. Extracted
selectAllText(in:app:) with that wait and routed both through it, and made the
Return tap check isHittable rather than mere existence.
Verified on both device families under the conditions that produced the
failures: 11/11 pass on iPhone and 11/11 on iPad, having failed 2 on iPhone
immediately before the change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copy-paste-ready submission materials for a normal (non-Xcode-Cloud) release:
- RELEASE-1.2.md master checklist + local archive/upload + Git Flow steps
- app-store-release-kit-1.2.md every App Store Connect field, validated to
Apple's character limits, plus review notes,
category, age rating, and hosted URLs
- press-kit-1.2.md fact sheet, journalist pitch, Product Hunt copy,
Apple editorial nomination, social launch posts
- testflight-1.2-what-to-test.md the TestFlight tester message (full + short)
Privacy Policy and Marketing URLs are now live via GitHub Pages
(gh-pages branch): privacy.html mirrors PRIVACY.md, index.html is a themed
landing page. Both return HTTP 200.
Spanish App Store Connect metadata already lives in app-store-localization-es.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SpyLegacyRepository was declared @unchecked Sendable but mutated savedNotes with no synchronization, while its sibling SpyNoteRepository (NoteStoreTests) guards the identical state with an NSLock. No test exercises it concurrently today, so no race manifests -- but the @unchecked Sendable claim should be backed by real synchronization. Match the sibling's pattern. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rewrote every em dash out of the docs, README, CONTRIBUTING, and a few source comments, replacing each with the punctuation that actually fits the sentence rather than a mechanical swap. Also trimmed a handful of AI-sounding passages: staged contrasts, a forced fragment triad, and some meta-commentary that referenced the writing process instead of the app. Fixed two stale references left over from earlier in the release work: the release checklist and release kit both still pointed at the interim GitHub Pages privacy URL after the site moved to the branded cheatsheet.apphq.online domain. No factual content changed. Character counts on App Store Connect fields were rechecked and corrected where a dash removal shifted the count by a character or two. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Lists weskcode@duck.com alongside the GitHub issues link in PRIVACY.md, the press kit fact sheet, and the App Store release kit. Also adds a note in the release kit that App Store Connect's App Review Contact Information (a separate field from the public Support URL) should use this same address. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
GitHub Actions never produced a submittable archive for this project, it only ran build and test checks. macOS runners bill Actions minutes at a 10x multiplier on every GitHub plan, and the account backing this repo is now on the Free tier (2,000 minutes a month for a private repo), which leaves almost no room for iOS work at that rate. Xcode Cloud comes with its own Apple Developer Program build-hour allotment, does the same build and test work, and can also sign and deliver straight to TestFlight, something the old pipeline could never do. Removed ------- .github/workflows/ci.yml and its composite action. The whole workflow ran on macos-26 runners for every job, including the cheap toolchain-free checks, so there was no lint-only job to keep. Added ----- ci_scripts/ci_post_clone.sh regenerates the gitignored Xcode project from project.yml on every Xcode Cloud clone, then runs the same three fast checks the old GitHub Actions pipeline ran before its simulator work: verify-build-sdk.sh, verify-project-config.sh, and verify-localization.sh. .xcode-version pins 26.6 for local tooling. Xcode Cloud's own Environment tab, not this file, is what actually governs which Xcode a workflow builds with; real-world reports say Xcode Cloud does not always honor a committed version file, so the two are documented separately rather than treated as one mechanism. Updated ------- CONTRIBUTING.md, README.md, Docs/os-support-policy.md, and Docs/RELEASE-1.2.md no longer describe the GitHub Actions pipeline or its Xcode-selection mechanics. Docs/RELEASE-1.2.md's signing section is rewritten for Xcode Cloud's managed signing, which does not depend on a certificate in a local keychain the way a manual archive and upload did. Setting up the actual Xcode Cloud workflow in App Store Connect still needs a person with the Apple Developer account; steps are in Docs/RELEASE-1.2.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Follow-up to the previous commit, which removed GitHub Actions but was missing its own replacement files due to a broken git add invocation. This adds what should have shipped together with that removal. ci_scripts/ci_post_clone.sh regenerates the gitignored Xcode project from project.yml on every Xcode Cloud clone, then runs the same three fast checks the old GitHub Actions pipeline ran before its simulator work: verify-build-sdk.sh, verify-project-config.sh, and verify-localization.sh. .xcode-version pins 26.6 for local tooling. Xcode Cloud's own Environment tab, not this file, is what actually governs which Xcode a workflow builds with. CONTRIBUTING.md, README.md, Docs/os-support-policy.md, and Docs/RELEASE-1.2.md no longer describe the GitHub Actions pipeline or its Xcode-selection mechanics. Docs/RELEASE-1.2.md's signing section now describes Xcode Cloud's managed signing instead of a local archive and manual Organizer upload. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- compose_screenshot.py gains a mac device treatment (thin near-square bezel, no camera cutout) - three 2880x1800 shots from the seeded demo build: split view, instant search, 30-day trash - release kit and final README updated; mac slot is no longer an open item
…t findings Full UI/UX/accessibility audit and fix pass: - Fix NavigationSplitView's sidebar silently collapsing after creating a note by pinning columnVisibility to .all; this also made the system "Show/Hide Sidebar" command actually functional for the first time. - Rebuild onboarding around the real note preview instead of a generic icon-in-circle row template (owner-approved direction). - Scope the Trash "Back to Notes" button to only render where it doesn't duplicate iOS's system back chevron; keep it on macOS/iPad where it's the only way back. - Add a Settings entry point on iOS/iPadOS -- there was none before, so dismissing the widget hint there was permanent with no way to undo it. - Block onboarding's swipe-to-dismiss so it can't skip marking itself complete, which was causing it to reappear on every launch. - Unify save/load retry into one action; the retry banner (converted to an alert on iOS) now covers save failures too, not just load failures. - Stop misreporting a widget-snapshot save failure as "your note didn't save" when the note itself saved fine. - Make the widget's per-family line limit scale with the note text size setting and add a "+N more" indicator so long notes don't clip silently; the widget background now follows the pinned note's actual color, matching onboarding's own claim. - Flush pending saves before macOS quits (NSApplicationDelegateAdaptor) so a ⌘Q right after typing can't drop the last debounced save. - Add the missing Spanish translation for "Hide" and close the gap in verify-localization.sh that let it through -- it now scans every source file in both targets plus literal Text/Button/Label/Toggle strings, not just stable dotted keys. - Soften the checklist "ghost circle" opacity on non-task lines, restyle Settings to standard Form Sections, align Trash/editor content padding so it doesn't jump on iPad, add accessibility-element grouping to the icon-only color swatch and pin buttons. - Misc: fix the app tint color to match the real accent color instead of system blue, remove dead code (LiquidGlassGroup, unused after the onboarding rebuild), add justification comments to four @unchecked Sendable conformances, drop a redundant state reassignment. Verified: macOS and iOS builds clean, 69/69 unit tests pass, verify-localization.sh and verify-project-config.sh both pass. Three blockers (sidebar collapse, missing accessibility labels, trash-restore data loss) were checked live against the running app -- the first is fixed and confirmed, the third didn't reproduce and no code path supports it, and the second is a suspected macOS 26 beta SDK accessibility-bridging issue that survived two different code-level fixes and needs re-verification with VoiceOver on a non-beta OS. Not touched, needs explicit sign-off per this repo's persistence and architecture policies: a SwiftData migration plan for PersistedCheatSheetNote, and moving Color/SwiftUI helpers out of the Shared model layer. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ompt Sends aggregate, anonymous usage signals only (e.g. "a note was pinned"), never note content. Signals are a no-op until AnalyticsService.appID is replaced with a real TelemetryDeck App ID. Declares the new collected data type in PrivacyInfo.xcprivacy and discloses it in PRIVACY.md, README.md, and the 1.2 App Store release kit. Also prompts for a StoreKit review once a user has pinned 5 distinct notes, at most once per install. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same gap as develop: Xcode Cloud disables automatic SPM resolution and needs a resolved manifest already in place before it will build. release/1.2 pins the same TelemetryDeck 2.14.2 as develop, so the same pin applies. Commit it under ci_scripts/ and have ci_post_clone.sh copy it into place right after xcodegen generates the project.
On compact iPhone layouts the palette picker shared a row with the font, size, and pin controls and could push the pin button off screen. Put the palette on its own row, move the pin button into a shared property, and have the style-and-pin UI test assert the title field and pin button sit inside the app frame.
Add the checklist, text size, and per-note captures, hide widget hints, and replace the silent `if exists` fallbacks with XCTFail so a missing control fails the run instead of producing a short screenshot set.
render_final.py builds every iPhone and Mac screenshot from captions.tsv using the centered-caption layout. Rewrite the final/ README to match the ten-plus-ten set, and ignore the Python bytecode cache.
…mages iPhone images are 1320x2868 and Mac images are 2880x1800, all RGB with no alpha. The iPad images from the earlier set are unchanged.
Replace the Git Flow description in CONTRIBUTING.md and the OS support policy with a main-only flow, keeping gh-pages as the Pages host. Update the release checklist for the 20-image screenshot set, the header layout fix, and the re-run test results, and drop the develop back-merge steps. Point the screenshot capture command at an installed simulator.
Use colons, commas, and periods instead. No change to the facts stated.
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merges the
release/1.2line intomain.mainwas 28 commits behind it.What it contains
#, such as# C#, keep the hash in the editor and the widget.Version
project.ymlat merge says 1.0 (16) from the relabel commit, while the release docs say 1.2. This PR does not settle that.Verification
Run locally on 2026-10-01 against the Xcode 27 beta SDK:
Not run: the iPad UI suite and an Xcode 26 archive. The iOS TestFlight archive on
6e34368failed at export because the widget App ID could not be signed with its App Group.