# Repository instructions ## Gitea issue workflow Use this repository's `gotcha` CLI to list, inspect, create, update, comment on, and close Gitea issues. Run it from the repository root so the configured Git remote selects the server and repository: ```sh cargo run -q -p gotcha-cli -- issue list cargo run -q -p gotcha-cli -- issue list --milestones "first feature complete release" cargo run -q -p gotcha-cli -- issue show 7 cargo run -q -p gotcha-cli -- issue comment 7 < comment.txt cargo run -q -p gotcha-cli -- issue close 7 ``` Use `gotcha issue list --help` for state, kind, keyword, label, milestone, author, assignee, mention, date, and pagination filters. Grant network access before invoking commands that contact Gitea in a sandboxed runner. ## Required pre-commit gates Run every gate below from the repository root before committing. Every command must succeed; do not commit code that is unformatted, fails Clippy, or compiles with warnings. ```sh cargo fmt --all -- --check RUSTFLAGS="-D warnings" cargo check --workspace --all-targets cargo clippy --workspace --all-targets -- -D warnings cargo test --workspace ``` Do not weaken or skip these gates to make a commit pass. Fix the underlying warning, lint, formatting issue, or test failure. ## Rust and Swift ownership boundary Rust owns all application behavior. Put networking, authentication, input validation, persistence, preference changes, filtering, sorting, aggregation, parsing, content classification, display-data formatting, and navigation target derivation in `crates/app`. Cover non-trivial behavior there with Rust tests and expose view-ready records and operations through UniFFI. Swift is the native iOS presentation layer. Limit `ios/Sources` to UIKit and SwiftUI lifecycle, view-controller navigation, native controls, layout, drawing, fonts, colors, symbols, accessibility, task cancellation tied to view lifetime, and Apple presentation integrations such as Quick Look. Swift may map Rust-provided states to visual treatments and maintain transient control state; it must not infer domain state from display strings, duplicate Rust transformations, classify content, or implement persistence and API behavior. When changing iOS functionality: - Trace the complete flow before editing and implement behavior in Rust first. - Prefer view-ready Rust records over exposing raw Gitea models or rebuilding titles, summaries, selections, progress, and categories in Swift. - Treat a pure Swift helper that does not require an Apple UI framework as a boundary warning; move it to Rust unless it only calculates view geometry. - Regenerate and commit the UniFFI Swift and C bindings whenever the exported Rust interface changes. - During review, inspect both sides of the bridge and reject new business logic added to Swift merely because its caller is a view controller. ## UI verification conventions `TESTING.md` is the source of truth for iOS visual verification and the release regression suite. - Update `TESTING.md` in the same commit whenever UI appearance, behavior, navigation, or interaction changes so its scenarios remain current. - For each ordinary commit, run every `TESTING.md` scenario relevant to the changed UI in addition to the required pre-commit gates. Report which visual scenarios were exercised. - When asked to perform a release test, run the complete `TESTING.md` checklist. Every scenario must succeed before reporting release sign-off; record failures and resolve release blockers instead of skipping them. ## iOS simulator build and deployment This Apple Silicon project builds the simulator app for `arm64`. Do not disable code signing: the Rust build script consumes Xcode's generated simulator entitlement paths. Do not request an `x86_64` simulator build unless the `x86_64-apple-ios` Rust target has explicitly been installed. Use this sequence from the repository root: ```sh cd ios xcodegen generate xcodebuild \ -project Gotcha.xcodeproj \ -scheme Gotcha \ -configuration Debug \ -sdk iphonesimulator \ -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ ARCHS=arm64 \ ONLY_ACTIVE_ARCH=YES \ build gotcha_build_dir="$( xcodebuild \ -project Gotcha.xcodeproj \ -scheme Gotcha \ -configuration Debug \ -sdk iphonesimulator \ -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ -showBuildSettings -json \ ARCHS=arm64 \ ONLY_ACTIVE_ARCH=YES | plutil -extract 0.buildSettings.TARGET_BUILD_DIR raw -o - - )" xcrun simctl install booted "$gotcha_build_dir/Gotcha.app" xcrun simctl launch booted de.rfc1437.gotcha ``` Before deploying, check for a booted simulator with `xcrun simctl list devices available`. If none is booted, boot an available iPhone (currently `xcrun simctl boot "iPhone 17 Pro"`) and open Simulator. CoreSimulator access may require running `xcodebuild` and `simctl` outside the workspace sandbox. ## Post-issue release deployment After an issue is verified, committed, pushed, commented on, and closed, deploy the completed version according to the code it changes: - For CLI changes, build `gotcha-cli` in release mode and install the resulting `gotcha` executable in `~/.local/bin/` so the command is available on `PATH`. - For iOS app changes, install the completed app on the currently paired iPhone. - The Gitea crate is shared by the CLI and iOS app, so changes to that crate also require installing the completed app on the paired iPhone. A purely CLI change does not require an iPhone deployment. If an issue changes both release surfaces, perform both deployments. ## Generated build data Use Xcode's default DerivedData location; do not pass `-derivedDataPath`. Cargo's ignored `target/` directory is a disposable build cache. Cargo does not bound or garbage-collect stale target artifacts, so check it with `du -sh target` and run `cargo clean` when disk space is worth a full rebuild. Do not add a custom cache-pruning tool or disable incremental compilation just to reduce routine cache usage.