# 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. ## Gitea, app, CLI, and Swift ownership boundary `gotcha_gitea` owns Gitea networking and authentication plus the behavior of Gitea objects: validation, pagination, name-to-ID resolution, mutations, ownership checks, object relationships, activity targets, commit graphs, and diff parsing. The app and CLI must not import generated Gitea API modules or build generated-client configurations. Add a concrete `Client` operation to `gotcha_gitea` instead. Generated response models may cross the boundary when a frontend only needs to present their fields; the CLI's explicit `api request` command is the sole low-level escape hatch. `crates/app` owns application state, persistence, preferences, favorites, content classification, navigation targets, and view-ready UniFFI records. The CLI owns argument and YAML parsing plus terminal formatting. Do not duplicate Gitea object transformations or relationship handling in either frontend. 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 Gitea behavior in `gotcha_gitea` and app behavior in `crates/app` 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 handling After an issue is verified, committed, pushed, commented on, and closed, handle 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, validate the completed app in the simulator. Never install an Xcode-run or otherwise development-signed build on a physical iPhone; this would replace the correctly signed AltStore PAL installation. - Physical iPhone installs and updates must use the complete AltStore PAL release process: create and validate a distribution-signed Release archive, submit it for notarization, publish the accepted Alternative Distribution Package and source update, then install or update Gotcha through AltStore PAL. - Publishing an AltStore PAL release is not an automatic per-issue step. Perform it only when the user explicitly requests and authorizes release publication. - The Gitea crate is shared by the CLI and iOS app, so changes to that crate also require simulator validation and inclusion in the next authorized AltStore PAL release. A purely CLI change does not require iOS validation. If an issue changes both release surfaces, install the CLI release and validate the iOS app in the simulator. ## 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.