commit e25819267b51f659e5dfdf7b318239a8969bf45c
parent 7831fd97f101b4e6516c92e947db4801f7fd33eb
Author: triesap <tyson@radroots.org>
Date: Tue, 8 Sep 2026 17:09:38 +0000
tera: anchor approved application ownership
- Define app-owned Rust, Today and Add boundaries while preserving shared owners.
- Evaluate the standalone Cargo graph and reject foreign members and local dependencies.
- Exercise forbidden-root, symlink and installed-artifact tampering guards.
- Pass 43 package tests, fixture validators, maintainability and locked Rust checks.
Diffstat:
4 files changed, 211 insertions(+), 4 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
@@ -8,6 +8,10 @@ This file applies to the complete standalone iOS app repository. A closer
- 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.
+ It also owns application Rust policy, runtime transitions, durable authored
+ operation orchestration and application FFI. Keep one root Rust workspace;
+ application packages belong under `core/crates`. The current exact Lib pin
+ temporarily supplies those packages until their ordered history transfer.
- `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
@@ -28,12 +32,20 @@ This file applies to the complete standalone iOS app repository. A closer
## Product and security boundaries
-- The app is an iOS client. It owns Apple presentation, lifecycle callbacks,
+- The product has exactly two bottom tabs, Today and Add, and retains its five
+ current creation families. Cached Today and local Add must remain usable
+ independently of network readiness. Do not activate farm, CRDT, commerce,
+ additional transports or unrelated product surfaces through this refactor.
+- The Swift host 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.
+- Application validation, transitions, durable receipts and app-facing FFI
+ models belong to this application's Rust packages. Shared domain types,
+ signing protocols, transport and storage mechanics stay in their existing
+ public producer packages at exact pins. Swift translates and presents those
+ contracts; it must not fork canonical policy or own a second database.
+- Branding changes must preserve installed bundle/Keychain identities,
+ persisted schema and hash namespaces, and frozen signed operation identities.
- 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.
diff --git a/README.md b/README.md
@@ -6,6 +6,20 @@ exactly two bottom tabs: Today for discovery and Add for authored operations.
The current public release is `0.1.0-alpha`.
+Tera owns the application's Rust validation, runtime transitions, durable
+authored operations and application FFI as well as the native iOS host. Shared
+domain types, signing protocols, transport and storage mechanics remain in the
+public foundation packages. The target behavior keeps cached Today and local
+Add usable independently of network readiness; the native host presents the Rust contracts and supplies
+Apple platform capabilities.
+
+Application Rust packages belong under `core/crates` in the single root Cargo
+workspace. During the ordered ownership transfer, the existing source-lock shim
+and installed FFI still consume the exact pinned Lib revision. This transition
+preserves the current five creation families, Today/Add tabs, installed identity
+and persisted operation formats. Each moved package replaces its old source
+only with verified history, compatibility and generated-artifact evidence.
+
## Requirements
- macOS with Xcode and an iOS 18-or-newer simulator
@@ -177,6 +191,10 @@ of the release lane.
`make package-contract-check` evaluates the Swift package manifest and parses
the TOML, plist, JSON, xcconfig, project-package, and lock inputs as structured,
bounded data. It also runs the locked fixture and verifier unit suites.
+The check evaluates Cargo's workspace graph and rejects members or local
+dependencies outside this standalone repository, including implicit sibling
+checkouts. Human specifications and execution evidence remain outside the
+capsule and are never required by these checks.
Comments, examples, unreachable source, and arbitrary matching text cannot
satisfy a behavior-bearing package assertion; application behavior is proven
by the compiled Swift and simulator test lanes.
diff --git a/scripts/package_contract.py b/scripts/package_contract.py
@@ -335,6 +335,82 @@ def _verify_repository_layout(root: Path) -> None:
raise PackageContractError("forbidden public repository root exists")
+def _cargo_workspace(root: Path) -> dict[str, Any]:
+ with tempfile.TemporaryFile() as stdout, tempfile.TemporaryFile() as stderr:
+ try:
+ result = subprocess.run(
+ [
+ "cargo",
+ "metadata",
+ "--manifest-path",
+ str(root / "Cargo.toml"),
+ "--locked",
+ "--no-deps",
+ "--format-version",
+ "1",
+ ],
+ check=False,
+ stdin=subprocess.DEVNULL,
+ stdout=stdout,
+ stderr=stderr,
+ timeout=60,
+ )
+ except (OSError, subprocess.TimeoutExpired) as error:
+ raise PackageContractError("Cargo workspace cannot be evaluated") from error
+ stdout.seek(0)
+ output = stdout.read(MAX_CONTRACT_BYTES + 1)
+ if result.returncode != 0 or len(output) > MAX_CONTRACT_BYTES:
+ raise PackageContractError("Cargo workspace evaluation failed")
+ try:
+ value = json.loads(output)
+ except (UnicodeDecodeError, json.JSONDecodeError) as error:
+ raise PackageContractError("Cargo workspace output is malformed") from error
+ if not isinstance(value, dict):
+ raise PackageContractError("Cargo workspace output is not an object")
+ return value
+
+
+def _local_cargo_path(value: object, root: Path) -> Path:
+ if not isinstance(value, str) or not value:
+ raise PackageContractError("local Cargo path is invalid")
+ path = Path(value).resolve()
+ if not path.is_relative_to(root.resolve()):
+ raise PackageContractError("local Cargo path escapes the standalone repository")
+ return path.relative_to(root.resolve())
+
+
+def _validate_app_workspace(document: dict[str, Any], root: Path) -> None:
+ _exact(document.get("workspace_root"), str(root), "Cargo workspace root")
+ packages = document.get("packages")
+ members = document.get("workspace_members")
+ if not isinstance(packages, list) or not packages or not isinstance(members, list):
+ raise PackageContractError("Cargo workspace members are absent")
+ identifiers = [
+ package.get("id") for package in packages if isinstance(package, dict)
+ ]
+ if not all(isinstance(item, str) for item in identifiers + members):
+ raise PackageContractError("Cargo workspace member identity is invalid")
+ _exact(sorted(identifiers), sorted(members), "Cargo workspace member inventory")
+ for package in packages:
+ _validate_app_package(_mapping(package, "Cargo package"), root)
+
+
+def _validate_app_package(package: Mapping[str, Any], root: Path) -> None:
+ manifest = _local_cargo_path(package.get("manifest_path"), root)
+ directory = manifest.parent
+ if directory != Path("crates/source_lock") and not directory.is_relative_to(
+ "core/crates"
+ ):
+ raise PackageContractError("application Rust package is outside its owned root")
+ dependencies = package.get("dependencies")
+ if not isinstance(dependencies, list):
+ raise PackageContractError("Cargo dependency inventory is absent")
+ for dependency in dependencies:
+ item = _mapping(dependency, "Cargo dependency")
+ if "path" in item:
+ _local_cargo_path(item["path"], root)
+
+
def _verify_cargo_and_source(root: Path) -> tuple[str, str]:
cargo = _read_toml(root / "Cargo.toml")
workspace = _mapping(cargo.get("workspace"), "Cargo workspace")
@@ -525,6 +601,7 @@ def _verify_required_files(root: Path) -> None:
def verify(repo_root: Path) -> tuple[str, str]:
root = repo_root.resolve()
_verify_repository_layout(root)
+ _validate_app_workspace(_cargo_workspace(root), root)
release_version, _ = _verify_cargo_and_source(root)
apple_revision = _verify_apple_dependencies(root)
_verify_apple_configuration(root)
diff --git a/scripts/test_package_contract.py b/scripts/test_package_contract.py
@@ -1,9 +1,13 @@
from __future__ import annotations
import copy
+import hashlib
import json
import plistlib
+import shutil
+import subprocess
import sys
+import tempfile
import unittest
from pathlib import Path
@@ -15,6 +19,102 @@ import package_contract as contract # noqa: E402
class PackageContractTests(unittest.TestCase):
+ def workspace(self, root: Path, member: str = "core/crates/tera_core") -> dict:
+ return {
+ "workspace_root": str(root),
+ "workspace_members": ["app"],
+ "packages": [
+ {
+ "id": "app",
+ "manifest_path": str(root / member / "Cargo.toml"),
+ "dependencies": [],
+ }
+ ],
+ }
+
+ def test_application_workspace_accepts_owned_rust_and_transition_shim(self) -> None:
+ root = SCRIPTS.parent.resolve()
+ for member in ("core/crates/tera_core", "crates/source_lock"):
+ contract._validate_app_workspace(self.workspace(root, member), root)
+
+ def test_application_workspace_rejects_hidden_sibling_dependency(self) -> None:
+ root = SCRIPTS.parent.resolve()
+ document = self.workspace(root)
+ document["packages"][0]["dependencies"] = [
+ {"path": str(root.parent / "lib/crates/storage")}
+ ]
+ with self.assertRaisesRegex(contract.PackageContractError, "escapes"):
+ contract._validate_app_workspace(document, root)
+
+ def test_application_workspace_rejects_foreign_member_root(self) -> None:
+ root = SCRIPTS.parent.resolve()
+ with self.assertRaisesRegex(contract.PackageContractError, "owned root"):
+ contract._validate_app_workspace(
+ self.workspace(root, "private/runtime"), root
+ )
+
+ def test_application_workspace_rejects_implicit_parent_workspace(self) -> None:
+ root = SCRIPTS.parent.resolve()
+ document = self.workspace(root)
+ document["workspace_root"] = str(root.parent)
+ with self.assertRaisesRegex(contract.PackageContractError, "workspace root"):
+ contract._validate_app_workspace(document, root)
+
+ def test_application_workspace_rejects_symlink_escape(self) -> None:
+ with tempfile.TemporaryDirectory() as directory:
+ root = Path(directory).resolve()
+ (root / "core").symlink_to(root.parent, target_is_directory=True)
+ with self.assertRaisesRegex(contract.PackageContractError, "escapes"):
+ contract._validate_app_workspace(self.workspace(root), root)
+
+ def test_forbidden_roots_still_rejected(self) -> None:
+ with tempfile.TemporaryDirectory() as directory:
+ root = Path(directory)
+ for name in ("docs", ".github", ".act"):
+ with self.subTest(name=name):
+ forbidden = root / name
+ forbidden.mkdir()
+ with self.assertRaisesRegex(
+ contract.PackageContractError, "forbidden"
+ ):
+ contract._verify_repository_layout(root)
+ forbidden.rmdir()
+
+ def test_installed_artifact_guard_rejects_tampered_binary(self) -> None:
+ with tempfile.TemporaryDirectory() as directory:
+ root = Path(directory)
+ script = root / "RadrootsFFI/scripts/verify-installed-artifacts.sh"
+ script.parent.mkdir(parents=True)
+ shutil.copyfile(
+ SCRIPTS.parent / "RadrootsFFI/scripts" / script.name, script
+ )
+ library = (
+ root
+ / "Radroots/Frameworks/RadrootsFFI.xcframework/ios-arm64/libradroots_mobile_ffi.a"
+ )
+ library.parent.mkdir(parents=True)
+ fixture = b"synthetic artifact verifier fixture, not executable code"
+ library.write_bytes(fixture)
+ (root / "RadrootsFFI/source.lock").write_text(
+ "override RADROOTS_FIELD_FFI_DEVICE_SHA256 := "
+ + hashlib.sha256(fixture).hexdigest()
+ + "\n"
+ )
+ for data, expected in (
+ (fixture, "missing simulator FFI library"),
+ (fixture + b"tampered", "stale device FFI library"),
+ ):
+ library.write_bytes(data)
+ result = subprocess.run(
+ ["sh", str(script)],
+ check=False,
+ capture_output=True,
+ text=True,
+ timeout=10,
+ )
+ self.assertEqual(result.returncode, 1)
+ self.assertIn(expected, result.stderr)
+
def test_current_package_contract_is_structurally_exact(self) -> None:
version, revision = contract.verify(SCRIPTS.parent)
self.assertEqual(version, "0.1.0-alpha")