field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

commit dbfd099b0cbfe99070f8b4172c0236f939d54901
parent 3e8182889c0af630b8d32d43baf7c326ddcfaa7e
Author: triesap <tyson@radroots.org>
Date:   Fri, 14 Aug 2026 04:05:52 +0000

docs: enforce standalone iOS authority

- add capsule-local agent guidance for the current source boundary
- keep human specifications and qualification evidence parent-owned
- reject forbidden docs and workflow roots during package validation
- remove the duplicated lifecycle checklist after verifying its parent copy

Diffstat:
AAGENTS.md | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ddocs/shared-engine-lifecycle-smoke-checklist.md | 44--------------------------------------------
Mscripts/verify-package-contract.sh | 8++++++++
3 files changed, 118 insertions(+), 44 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md @@ -0,0 +1,110 @@ +# Radroots iOS app agent specification + +This file applies to the complete standalone iOS app repository. A closer +`AGENTS.md` overrides it for its subtree. + +## Authority and repository boundary + +- This capsule owns the public iOS application, its Swift package, generated + Xcode project, Apple host lifecycle, app state and views, FFI installation + boundary, privacy manifest, public API snapshot, and standalone validation. +- `radroots.lib.source-lock.v1.toml`, `Cargo.toml`, and + `RadrootsFFI/source.lock` must select the same exact remotely reachable public + lib revision and release version. `Package.swift`, both + `Package.resolved` files, and `project.yml` own exact Apple package inputs. +- `RadrootsFFI/provenance.json`, `RadrootsFFI/api/**`, `api/**`, generated + project/source inputs, and the package locks are machine evidence. Do not + hand-edit generated bindings, XCFramework contents, provenance, project + output, or API snapshots. +- Human specifications, decisions, migration history, runbooks, and + qualification evidence are parent-owned under `docs/oss/ios_app/**`. They + are absent from a standalone clone and must never become a build, test, + package, generation, or release input for this capsule. +- `docs/**`, `.github/**`, and `.act/**` are forbidden tracked roots. Public + commands remain forge agnostic; cross-repository workflow proof belongs only + to the parent workspace's root `.act/**` surface. +- Do not depend on non-public parent paths, non-public contracts, implicit + sibling checkouts, floating branches/tags, or unrecorded local artifacts. + +## Product and security boundaries + +- The app is an iOS client. It owns Apple presentation, lifecycle callbacks, + user-presence prompts, Keychain integration, foreground/background + scheduling, and translation between generated SDK DTOs and view state. +- Canonical domain policy, signing protocol, relay semantics, durable engine + state, wire contracts, and generated FFI models remain owned by their public + producer packages. Do not fork them into Swift application models. +- Keep identity secrets in the Apple credential boundary. Never log, snapshot, + serialize, fixture, or expose secret material, raw private event content, + credentials, tokens, private paths, or unsafe internal errors. +- Background work is host-owned, explicit, bounded, cancelable, and recoverable + across app lifecycle changes. Do not add hidden workers, process-global + runtime ownership, implicit relays, or direct database authority. +- Services-hardening generated changes must adopt the approved four coverage + states and three outcomes across Swift and FFI together. Do not retain + prototype evidence, receipt, outcome, or compatibility aliases. + +## Generated and project files + +- Change canonical producer contracts and generators before regenerating FFI + or SDK output. Inspect every generated diff and run freshness/API checks. +- `scripts/generate-project.sh` owns `Radroots.xcodeproj`; edit `project.yml` + and canonical source inputs rather than hand-editing generated project data. +- `RadrootsFFI/scripts/verify-installed-artifacts.sh` must reject missing, + stale, mismatched, or unproven FFI installations before Swift/Xcode work. +- Keep SwiftPM and Xcode workspace resolved revisions synchronized. Never allow + automatic dependency updates to select release inputs. +- Repository scripts must keep Xcode derived data and source/package caches, + SwiftPM scratch/cache output, and Cargo target output under extbuild-owned + paths. `RadrootsFFI/.build/out/**` and `RadrootsFFI/.radroots/source/**` are + ignored, rebuildable repo-local staging/source cache; they are never + canonical source, tracked output, or independent release authority. + +## Working and verification rules + +- Inspect `git status --short`, relevant locks/contracts, package/project + manifests, source, tests, scripts, generated artifacts, and snapshots before + editing. Preserve unrelated work. +- Run `cargo extbuild doctor` before the first mutating build, test, check, + dependency, package, generation, or snapshot command, then use the + repository's Make/script surfaces, which route work through + `cargo extbuild run -- ...`. +- `make package-contract-check` is the narrow standalone source-lock, + package-lock, privacy, version, and forbidden-root guard. +- `make bootstrap` performs networked source/artifact bootstrap. `make verify` + is the complete package, Xcode build/test, UI, and API-snapshot lane. Use an + explicitly installed simulator name when the default is unavailable. +- Run the smallest credible target while iterating, followed by the complete + affected standalone lane. Never claim a command passed unless it ran + successfully; report missing Xcode, simulator, signing, or network + prerequisites exactly. +- Prefer explicit typed state, deterministic transformations, bounded inputs, + narrow side effects, safe errors, and fail-closed validation. Avoid `unsafe` + and forced unwraps in production paths unless a local invariant is explicit + and tested. + +## Changes and external gates + +- Make one coherent, reviewable target-state change at a time. Keep source, + tests, machine contracts, generated outputs, locks, snapshots, and public + README material aligned. +- Use focused commit subjects in the repository's established imperative + style. +- Evidence that requires a normative product decision is recorded in the + parent-owned services-hardening authority, with the corresponding standalone + machine contract changed in the same ordered sequence. Do not create a local + human deviation ledger. +- Do not push, tag, publish packages, deploy, change signing identities, + profiles, entitlements, registry ownership, or credentials without separate + explicit authority. + +## Definition of done + +- The requested behavior is complete at the correct Apple-host, generated FFI, + package, project, or application boundary. +- Relevant package/Xcode/tool validation passed, generated output and locks are + fresh, public API snapshots agree, and zero `docs/**`, `.github/**`, or + `.act/**` roots exist. +- The final review finds no secret exposure, hidden runtime ownership, private + dependency, unrelated change, or unreported skipped lane, and records whether + the next sequence step is safe. diff --git a/docs/shared-engine-lifecycle-smoke-checklist.md b/docs/shared-engine-lifecycle-smoke-checklist.md @@ -1,44 +0,0 @@ -# Shared engine lifecycle smoke checklist - -Run this checklist on an iOS 18 or newer simulator after regenerating the FFI -artifact from `RadrootsFFI/source.lock`. Use a disposable app installation and -do not enter a production identity. - -## Automated prerequisite - -- Run the `Radroots` scheme unit tests on an arm64 simulator. -- Confirm the app and `SharedEngineLifecycleTests` both pass. -- Confirm the generated binding has no post-stream start, next, or stop API. - -## Host custody and prompts - -- Create a local identity and accept the Apple user-presence prompt. -- Background and foreground the app; confirm the identity remains locked until - the Apple prompt succeeds and no secret appears in logs or diagnostics. -- Cancel the prompt once; confirm the UI reports a bounded error and does not - replace the selected Keychain item. -- Sign out; confirm the runtime identity is cleared while the Keychain-backed - identity remains available for a later unlock. -- Reset local identity; confirm the Keychain item, public metadata, pending - background work, and in-memory signer are all removed. - -## Relay, cancellation, and background behavior - -- Configure one valid relay and confirm read/write operations report - `Available`; no connection count is displayed or exported. -- Open and close the feed; confirm polling stops on disappearance and resumes - with bounded fetches when reopened. -- Send the app to the background during a fetch; confirm Apple background task - scheduling remains host-owned and the app returns without a stuck spinner. -- Terminate the app from the simulator switcher; confirm the next launch starts - a fresh runtime and requires host restoration of the selected identity. - -## Logging and error presentation - -- Exercise invalid secret, invalid relay, and unavailable network paths. -- Confirm SDK errors are presented through their secret-safe message and - capability category, with no secret, raw event payload, or private path in - unified logging, file logging, diagnostics JSON, or the UI. -- Export diagnostics and confirm format - `radroots_field_ios_diagnostics_v2` contains only configured relays, - categorical source/sink availability, and the bounded last error. diff --git a/scripts/verify-package-contract.sh b/scripts/verify-package-contract.sh @@ -6,6 +6,14 @@ package="$repo_root/Package.swift" source_lock="$repo_root/RadrootsFFI/source.lock" consumer_lock="$repo_root/radroots.lib.source-lock.v1.toml" +for forbidden_root in docs .github .act +do + if [ -e "$repo_root/$forbidden_root" ] || [ -L "$repo_root/$forbidden_root" ]; then + echo "error: forbidden public repository root exists: $forbidden_root" >&2 + exit 1 + fi +done + make_value() { key=$1 awk -v key="$key" '$2 == key && $3 == ":=" { print $4 }' "$source_lock"