sdk

Radroots SDK and bindings
git clone https://radroots.dev/git/sdk.git
Log | Files | Refs | README

commit 1eddc04c67498d5412a89668e04a8cb9694c3eea
parent bcda74b3ebfff3f711670cc25b7910f27360fba7
Author: triesap <tyson@radroots.org>
Date:   Sun,  9 Aug 2026 06:29:50 +0000

contracts: relocate standalone documentation authority

Diffstat:
MAGENTS.md | 185+++++++++++++++++++++++++++++++++++++++++++------------------------------------
MCONTRIBUTING.md | 82+++++++++++++++++++++++++++++++++++++++++++------------------------------------
MREADME | 18+++++++++++++++---
Rdocs/api/radroots-0.1.0-alpha.txt -> contracts/api_baselines/radroots-0.1.0-alpha.txt | 0
Rdocs/api/radroots_sdk-0.1.0-alpha.txt -> contracts/api_baselines/radroots_sdk-0.1.0-alpha.txt | 0
Rdocs/implementation/deviations.toml -> contracts/architecture/deviations.toml | 0
Rdocs/specs/radroots_crates_release_v1.dot -> contracts/crates/release_v1/radroots_crates_release_v1.dot | 0
Rdocs/specs/radroots_crates_release_v1.sha256 -> contracts/crates/release_v1/radroots_crates_release_v1.sha256 | 0
Rdocs/specs/radroots_crates_release_v1.toml -> contracts/crates/release_v1/radroots_crates_release_v1.toml | 0
Rdocs/specs/radroots_crates_release_v1_inventory.csv -> contracts/crates/release_v1/radroots_crates_release_v1_inventory.csv | 0
Acontracts/historical_authority.v1.json | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ddocs/api/README.md | 19-------------------
Ddocs/decisions/0001-public-api-leakage-migration-baseline.md | 36------------------------------------
Ddocs/engineering/ci.md | 47-----------------------------------------------
Ddocs/engineering/local-overrides.md | 16----------------
Ddocs/engineering/release-v1-breaking-changes.md | 23-----------------------
Ddocs/engineering/sdk-lifecycle-test-matrix.md | 19-------------------
Ddocs/engineering/sdk-native-api-migration.md | 33---------------------------------
Ddocs/engineering/sdk-package-conformance.md | 31-------------------------------
Ddocs/getting-started/rust.md | 10----------
Ddocs/implementation/COMPATIBILITY_SHIMS.md | 19-------------------
Ddocs/implementation/DEPENDENCY_RESOLUTION.md | 23-----------------------
Ddocs/implementation/DEVIATIONS.md | 53-----------------------------------------------------
Ddocs/implementation/FACADE_SUPERSEDED_SURFACE_AUDIT.md | 52----------------------------------------------------
Ddocs/implementation/HISTORY_PRESERVATION.md | 26--------------------------
Ddocs/implementation/PUBLICATION_FREEZE.md | 20--------------------
Ddocs/implementation/SDK_SUPERSEDED_SURFACE_AUDIT.md | 55-------------------------------------------------------
Ddocs/implementation/SDK_WORKSPACE_CONSUMERS.md | 43-------------------------------------------
Ddocs/implementation/STEP_REPORT_TEMPLATE.md | 58----------------------------------------------------------
Ddocs/implementation/TRACEABILITY.md | 22----------------------
Ddocs/platform/kotlin.md | 15---------------
Ddocs/platform/swift.md | 14--------------
Ddocs/specs/README.md | 40----------------------------------------
Ddocs/specs/radroots_crates_release_v1.md | 1589-------------------------------------------------------------------------------
Mpackage.json | 3++-
Atools/radroots_sdk_contract.mjs | 10++++++++++
Atools/radroots_sdk_contract.test.mjs | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools/radroots_sdk_contract_lib.mjs | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
38 files changed, 521 insertions(+), 2388 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md @@ -1,99 +1,116 @@ # Radroots SDK agent specification -This file applies to the full standalone SDK repository. Read -`CONTRIBUTING.md` for the contributor workflow. A closer `AGENTS.md` -overrides this file for its subtree. +This file applies to the complete standalone SDK repository. Read +`CONTRIBUTING.md` before editing. A closer `AGENTS.md` overrides this file for +its subtree. -## Source of intent +## Current authority -- Read `docs/specs/README.md` and - `docs/specs/radroots_crates_release_v1.md` before changing a public - package, dependency, feature, binding, or release control. -- The Markdown specification is normative. Its TOML catalog is the executable - package and dependency representation; the CSV and DOT files are review - aids. -- Current source and tests are implementation evidence. They do not silently - override `radroots.crates.release.v1`. -- Record any evidence-based plan deviation in - `docs/implementation/deviations.toml`, following - `docs/implementation/DEVIATIONS.md`, before proceeding. Validate it with - `cargo xtask architecture`. +- This capsule is an independently verifiable public generated-package and + source-lock consumer. Its Rust workspace contains only the unpublished + `radroots_sdk_source_lock` package; canonical Rust SDK implementation and + generators remain in the exact public `radrootslabs/lib` revision selected + by `radroots.lib.source-lock.v1.toml` and `Cargo.toml`. +- `radroots.lib.source-lock.v1.toml` is the exact lib source-lock authority. + `contracts/provenance/**`, `contracts/packages/**`, and + `contracts/exports/**` own generated artifact provenance and package/export + selection. +- `contracts/historical_authority.v1.json` owns the closed Release V1 machine + artifact inventory and its exact digests. Historical API baselines live at + `contracts/api_baselines/**`; other retained machine history lives below + `contracts/architecture/**` and `contracts/crates/release_v1/**`. +- Human specifications, decisions, migration history, and qualification + evidence are parent-owned under `docs/oss/sdk/**`. They are not present in a + standalone clone and must never become a build, test, generation, package, + or release input for this capsule. +- Current source, generated output, tests, and lockfiles are implementation + evidence. They do not silently override the selected source revision or + checked-in contracts. -## Repository operating model +## Repository boundary -- This repository owns the Radroots SDK workspace, including Rust SDK APIs, - generated language bindings, FFI layers, WebAssembly surfaces, package - metadata, and SDK validation flows. -- It owns `radroots_sdk` and the ordinary-user `radroots` facade. The 17 - lower release-v1 packages remain owned by the standalone - `radrootslabs/lib` repository. -- Do not make this repository responsible for downstream apps, private - layouts, deployment policy, or compatibility packages unless represented by - a public contract here. -- Keep commits and handoff language standalone and open-source-readable. Do - not reference private checkout structure or internal coordination context. -- Prefer the smallest coherent target-state change. Do not mix unrelated - cleanup, speculative abstraction, compatibility scaffolding, or roadmap work. -- `.github/**` and capsule-local CI workflows are forbidden. Keep validation - forge-agnostic; any required monorepo orchestration belongs exclusively to - the parent repository's root `.act/**` authority. +- Keep the repository standalone, forge agnostic, and open-source-readable. + Do not depend on a non-public parent path, non-public contract, local sibling + checkout, unpublished local artifact, or internal coordination context. +- Production source selection must use the exact remotely reachable public Git + revision recorded by both source-lock surfaces. Floating branches, tags, + local paths, and mismatched revisions are forbidden. +- The `.radroots-consumer-root` marker must remain exactly `sdk` followed by + LF. Source resolution must remain absolute, canonical, non-symlinked, and + explicitly supplied through `RADROOTS_LIB_SOURCE_ROOT`. +- `docs/**`, `.github/**`, and `.act/**` are forbidden tracked roots. Public + validation commands live in this repository; private cross-repository + orchestration belongs only to the parent repository's root `.act/**`. +- Do not make this repository responsible for private applications, + deployment policy, service runtime ownership, or compatibility packages. -## Preflight and engineering rules +## Generated artifacts and packages -- Inspect the relevant specs, manifests, implementation, tests, package - metadata, generators, and generated outputs before editing. -- Inspect `git status --short` and preserve unrelated work. -- Use checked-in repository commands and the narrowest validation that proves - the change; never claim a check passed unless it ran successfully. -- Work spec-first. Do not invent packages, bindings, exports, compatibility - layers, or publishing behavior. -- Prefer explicit typed models, deterministic behavior, narrow side effects, - and direct service boundaries over stringly or implicit behavior. -- Avoid hidden production panics. Use typed errors for expected failures. -- Avoid `unsafe` unless strictly necessary and document the local invariants. -- Do not expose secrets, private keys, credentials, tokens, private - identifiers, sensitive user data, or sensitive event content in code, logs, - tests, fixtures, docs, or examples. +- `tools/radroots_sdk_artifact.mjs` is the governed generation/check adapter. + It delegates generation and source-lock verification to the selected public + lib checkout through lib's `cargo xtask` surface. +- Generated artifacts are reproducible outputs of checked-in source locks, + package/export contracts, and producer generators. Do not hand-edit + `generated/**`, generated files under `packages/**`, provenance JSON, or + package source-lock output. +- Update generators and canonical contracts first, regenerate, inspect the + complete diff, and run freshness checks. Generated output never dictates a + native source model or creates a second source authority. +- Keep package manifests, the pnpm lockfile, provenance, exports, generated + source, and consumer-facing package READMEs synchronized. +- Do not reintroduce retired prototype evidence, outcomes, receipts, event + models, runtime contracts, or compatibility aliases. Services-hardening + generated changes must expose the approved four coverage states and three + outcomes together across every applicable language/package surface. -## Architecture and generation rules +## Working and verification rules -- `radroots_sdk` is the advanced front door. It owns host-neutral client - semantics, not global runtimes, hidden workers, logging installation, UI - state, Studio databases, or process lifecycle. -- `radroots` is a curated ordinary-user facade. It has no public `sdk` - namespace and does not wildcard-reexport `radroots_sdk`. -- Cross-repository dependencies on the lower package family use registry - versions in release candidates, never production sibling paths or Git - overrides. -- No public package has a dependency on a private or unpublished Radroots - package, including dev, build, optional, and target-specific edges. -- Own generated artifacts through checked-in schemas, generators, templates, - and public contracts. Do not hand-edit generated output. -- Generated bindings remain reproducible and do not mechanically dictate the - native Rust module layout. -- During migration, every package remains non-publishable until its - package-realistic release gates pass and publication is explicitly - authorized. Follow `docs/implementation/PUBLICATION_FREEZE.md`. +- Inspect `git status --short`, relevant contracts, package manifests, tools, + generated outputs, and tests before editing. Preserve unrelated work. +- Run `cargo extbuild doctor` before the first mutating build, test, check, + dependency, package, or generation command, then route it through + `cargo extbuild run -- ...`. +- `pnpm run contracts:check` validates the exact historical inventory and the + absence of forbidden public roots without requiring a lib checkout. +- `pnpm run test:tools` runs standalone tool and boundary tests. +- `pnpm run source:check` and generation/freshness commands require an exact + `RADROOTS_LIB_SOURCE_ROOT` matching the checked-in lock. `pnpm run check` is + the full generated-package lane. +- This repository has no local `cargo xtask` package. Do not document or invoke + nonexistent SDK-local xtask commands; the artifact adapter invokes the + selected producer's governed xtask explicitly. +- Use the narrowest check that proves a change while iterating, followed by the + complete affected standalone lane. Never claim a check passed unless it ran + successfully. +- Prefer explicit typed models, deterministic behavior, bounded inputs, narrow + side effects, and fail-closed validation. Avoid hidden production panics and + `unsafe`; if `unsafe` becomes unavoidable, document and test its invariants. +- Never expose secrets, credentials, tokens, private identifiers, sensitive + user data, or sensitive event content in source, logs, fixtures, generated + output, examples, or errors. -## Commits, deviations, and irreversible actions +## Changes, commits, and external gates -- Format commits as `<scope>: <lower-case imperative summary>`. -- Keep commits focused and reviewable. Use a blank line before a multi-line - body and `- ` bullets for notable changes and validation. -- If repository evidence proves a planned step obsolete or unsafe, record the - evidence, affected specification anchor, disposition, and validation in - `docs/implementation/deviations.toml`, following - `docs/implementation/DEVIATIONS.md`. A normative change also requires an - approved decision record. -- Do not publish crates or packages, create release tags, change registry - ownership, merge or rename repositories, merge pull requests, rotate - credentials, or mutate trusted-publisher configuration without explicit - authorization. +- Make one coherent, reviewable target-state change at a time. Do not mix + unrelated cleanup, speculative abstraction, compatibility scaffolding, or + roadmap work. +- Use commit subjects in the form `<scope>: <lower-case imperative summary>`. +- A machine-contract change must update its validator and negative tests in the + same checkpoint. A generated contract change must update all affected + outputs and consumer qualification evidence in its owning sequence. +- Repository evidence that invalidates an active parent specification is a + review finding to record in parent-owned authority; do not create a local + human deviation ledger or silently redefine behavior. +- Do not push, tag, publish packages, mutate registry ownership, change trusted + publishers, deploy, or perform credential operations without the separate + authority required for that external action. ## Definition of done -- The requested change is complete at the correct package boundary. -- Affected code, tests, contracts, generators, outputs, and docs agree. -- Relevant repository-owned validation passed or an exact blocker is reported. -- The final review records files changed, checks run, residual risks, and - whether the next step is safe. +- The change is complete at the source-lock, contract, generator, or package + boundary that owns it. +- Contracts, tools, tests, package metadata, generated outputs, and lockfiles + agree, with zero tracked `docs/**`, `.github/**`, or `.act/**` paths. +- Relevant standalone validation passed, exact failures are reported, the diff + contains no private dependency or unrelated change, and the next sequence + step is explicitly safe or blocked by a real external gate. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md @@ -1,48 +1,56 @@ # Contributing -Radroots SDK changes are contract-driven and independently reviewable. Before -editing, read these files in order: +Radroots SDK changes are contract-driven and independently verifiable. Before +editing, read `AGENTS.md`, then inspect the affected source lock, contracts, +package manifests, tools, generated outputs, and tests. -1. `AGENTS.md` -2. `docs/specs/README.md` -3. `docs/specs/radroots_crates_release_v1.md` for crate-surface work -4. the affected manifests, implementation, contracts, generators, and tests - -The release-v1 architecture identifier is `radroots.crates.release.v1`. This -repository owns `radroots_sdk` and the ordinary-user `radroots` facade; the -standalone core-library repository owns the other 17 public packages. +This repository is the public generated-package and source-lock consumer for +the Radroots SDK cohort. Canonical generator and Rust implementation source is +selected from `radrootslabs/lib` by the exact revision in +`radroots.lib.source-lock.v1.toml` and `Cargo.toml`. Human architecture and +execution authority is parent-owned under `docs/oss/sdk/**`; standalone +commands do not require that private parent documentation. ## Workflow -1. Inspect repository status and the current source authority. -2. Make one coherent, commit-sized change. -3. Update public contracts, tests, generators, checked-in outputs, and docs - with the implementation they govern. -4. Run the narrowest repository-owned checks that prove the change, followed - by the broader workspace or package lane required by its scope. -5. Review the staged diff for API leakage, private dependencies, generated - drift, secrets, hidden side effects, and unrelated changes. +1. Inspect repository status and the current machine authority. +2. Make one coherent, commit-sized change at the owning contract, tool, + generated-output, or package boundary. +3. If producer behavior changes, update the selected public lib source first, + then regenerate every affected SDK output from that exact reachable + revision. +4. Update contracts, tests, generated outputs, package metadata, and lockfiles + together. +5. Run the narrowest repository-owned checks that prove the change, followed + by the complete affected standalone lane. +6. Review the staged diff for source-lock drift, handwritten generated output, + stale provenance, private dependencies, forbidden roots, secrets, and + unrelated changes. + +Run `cargo extbuild doctor` before the first mutating verification command and +route repository checks through `cargo extbuild run -- ...`. The primary +commands are: -Use `cargo xtask check` for the repository-wide Rust and generated-package -lane where applicable. Run targeted format, check, test, Clippy, contract, and -generated-freshness commands while iterating. +```text +pnpm run contracts:check +pnpm run test:tools +pnpm run source:check +pnpm run check +``` -## Commits and deviations +The source and generation lanes require an absolute, canonical +`RADROOTS_LIB_SOURCE_ROOT` whose Git revision matches the checked-in source +lock. The contract and tool-test lanes remain usable without the parent +monorepo. This capsule has no local `cargo xtask` package. -Use this commit form: +## Commits and external actions -```text -<scope>: <lower-case imperative summary> -``` +Use `<scope>: <lower-case imperative summary>` for focused commits. Do not add +capsule-local human authority, `.github/**`, or `.act/**`; do not create a +compatibility path for a breaking generated contract. Record any required +normative decision in the parent-owned services-hardening authority and update +the corresponding standalone machine contract. -Keep commits focused and keep public commit language independent of any -private checkout. Do not publish, tag, merge, or change registry ownership -without explicit authorization. - -When current evidence proves a planned step obsolete or unsafe, follow -`docs/implementation/DEVIATIONS.md` and validate the machine-readable ledger -with `cargo xtask architecture`. Complete -`docs/implementation/STEP_REPORT_TEMPLATE.md`, and keep -`docs/implementation/TRACEABILITY.md` aligned with durable requirements. -Record the evidence and affected spec anchor before changing the plan; do not -silently redefine the architecture. +Do not push, tag, publish, deploy, change registry ownership or trusted +publishers, or perform credential operations without separate explicit +authorization. diff --git a/README b/README @@ -1,7 +1,18 @@ # radroots_sdk -This is the README for `sdk` which contains the Rad Roots SDK, including Rust runtime -APIs, generated bindings, FFI layers, and package surfaces. +This standalone public repository owns Radroots SDK generated package outputs, +package/export contracts, provenance, and the exact source lock that selects +their canonical public producer revision. + +The Rust workspace contains only the unpublished source-lock verification +capsule. Generated TypeScript, Wasm, Swift, and Kotlin surfaces are produced +through `tools/radroots_sdk_artifact.mjs` from the exact +`radrootslabs/lib` revision recorded in `radroots.lib.source-lock.v1.toml`. + +Use `pnpm run contracts:check` for standalone contract validation and +`pnpm run check` with an exact `RADROOTS_LIB_SOURCE_ROOT` for the complete +generated-package lane. See `AGENTS.md` and `CONTRIBUTING.md` for repository +rules and command requirements. ## Copyright @@ -11,4 +22,5 @@ Except as otherwise noted, all files in the `sdk` distribution are ## License -This repository is licensed under either MIT or Apache-2.0, at your option. See LICENSE-MIT and LICENSE-APACHE. +This repository is licensed under either MIT or Apache-2.0, at your option. +See LICENSE-MIT and LICENSE-APACHE. diff --git a/docs/api/radroots-0.1.0-alpha.txt b/contracts/api_baselines/radroots-0.1.0-alpha.txt diff --git a/docs/api/radroots_sdk-0.1.0-alpha.txt b/contracts/api_baselines/radroots_sdk-0.1.0-alpha.txt diff --git a/docs/implementation/deviations.toml b/contracts/architecture/deviations.toml diff --git a/docs/specs/radroots_crates_release_v1.dot b/contracts/crates/release_v1/radroots_crates_release_v1.dot diff --git a/docs/specs/radroots_crates_release_v1.sha256 b/contracts/crates/release_v1/radroots_crates_release_v1.sha256 diff --git a/docs/specs/radroots_crates_release_v1.toml b/contracts/crates/release_v1/radroots_crates_release_v1.toml diff --git a/docs/specs/radroots_crates_release_v1_inventory.csv b/contracts/crates/release_v1/radroots_crates_release_v1_inventory.csv diff --git a/contracts/historical_authority.v1.json b/contracts/historical_authority.v1.json @@ -0,0 +1,62 @@ +{ + "schema_version": 1, + "contract_id": "radroots.sdk.historical_authority.v1", + "status": "historical", + "source_revision": "bcda74b3ebfff3f711670cc25b7910f27360fba7", + "parent_human_owner": "docs/oss/sdk/release-v1-history", + "capsule_human_docs_forbidden": true, + "artifacts": [ + { + "path": "contracts/api_baselines/radroots-0.1.0-alpha.txt", + "role": "public_api_baseline", + "sha256": "e0c21fc096715fba3b3273bb1a8a880d6e871161772c5a1019404064aa0becb1" + }, + { + "path": "contracts/api_baselines/radroots_sdk-0.1.0-alpha.txt", + "role": "public_api_baseline", + "sha256": "97dfccb393fcc7953a59f0b12f03485daf9b7c625e9a4529fd883fcf0306e618" + }, + { + "path": "contracts/architecture/deviations.toml", + "role": "historical_deviation_ledger", + "sha256": "888d581264cddf6fe0b4a09a2171535094ef9fb3c422f7866e4e0c802359ea1f" + }, + { + "path": "contracts/crates/release_v1/radroots_crates_release_v1.dot", + "role": "historical_release_graph", + "sha256": "d47de10be596a4d33fee102a4f0617f66700b49515a75a1f42d62c9710043059" + }, + { + "path": "contracts/crates/release_v1/radroots_crates_release_v1.sha256", + "role": "captured_stale_checksum_manifest", + "sha256": "5759ceaae30a9435346320c2791cfda9eb1559b779ea79fd2e94810e14efa281" + }, + { + "path": "contracts/crates/release_v1/radroots_crates_release_v1.toml", + "role": "historical_release_catalog", + "sha256": "1dc18437200dcd65b52090493306f452dade89b5116401d71be4ba4127239b19" + }, + { + "path": "contracts/crates/release_v1/radroots_crates_release_v1_inventory.csv", + "role": "historical_release_inventory", + "sha256": "5020875c2cda4b2c9568c8b3f0fad5cd96756c3c779a72481a9652e558f77891" + } + ], + "retired_human_artifacts": [ + { + "former_path": "docs/decisions/0001-public-api-leakage-migration-baseline.md", + "parent_path": "docs/oss/sdk/release-v1-history/decisions/0001-public-api-leakage-migration-baseline.md", + "sha256": "c5f2367bc85c84ce5a3af0d066d3fc8dab6d4e9f1061bb6af35b15d9e4b6e2b1" + }, + { + "former_path": "docs/specs/radroots_crates_release_v1.md", + "parent_path": "docs/oss/sdk/release-v1-history/release-v1-specification.md", + "sha256": "6f98eb958a29921919147c44ff6a80565df367adf362f7ac872ce2588a09a1e5" + } + ], + "captured_checksum_manifest": { + "path": "contracts/crates/release_v1/radroots_crates_release_v1.sha256", + "status": "historical_stale_capture", + "current_digest_authority": "contracts/historical_authority.v1.json" + } +} diff --git a/docs/api/README.md b/docs/api/README.md @@ -1,19 +0,0 @@ -# Public API baselines - -These files are reviewed release artifacts for the standalone SDK capsule. -They contain the simplified (`-sss`) all-features API emitted by -`cargo-public-api`; private implementation items and automatically generated -trait noise are intentionally omitted. - -Regenerate either Rust front-door baseline from this repository root with: - -```sh -cargo public-api -p radroots_sdk --all-features -sss --color never -cargo public-api -p radroots --all-features -sss --color never -``` - -An API change is not accepted merely because the baseline can be regenerated. -Review additions, removals, and changed signatures against the relevant package -charter and versioning policy before replacing a baseline. The facade snapshot -must remain curated: it must not contain a `radroots::sdk` module, facade-owned -traits, or an undifferentiated copy of the advanced SDK surface. diff --git a/docs/decisions/0001-public-api-leakage-migration-baseline.md b/docs/decisions/0001-public-api-leakage-migration-baseline.md @@ -1,36 +0,0 @@ -# ADR 0001: Public API leakage migration baseline - -Status: accepted for the crates release V1 migration -Date: 2026-07-27 - -## Context - -The Release V1 architecture forbids generic public packages from exposing -SQLx, Tokio, Reqwest, Nostr SDK, keyring, or platform-specific implementation -types. The existing identity, Nostr, and Nostr Connect packages predate that -boundary and still expose a finite set of upstream Nostr types while -publication remains frozen. - -## Decision - -The synchronized API-boundary contract records only the reviewed findings -under exception IDs RCRV1-API-001, RCRV1-API-002, RCRV1-API-003, -RCRV1-API-004, RCRV1-API-005, RCRV1-API-006, RCRV1-API-007, and -RCRV1-API-008. - -Every exception is package-, source-, item-, forbidden-root-, and -observed-path-specific. New items, new upstream paths, SQLx, Tokio, Reqwest, -keyring, platform-specific types, or broader aliases remain forbidden. The -exceptions authorize no publication. - -The identity exceptions must be removed by the Step 042 conformance gate, the -Nostr SDK exceptions by Step 124, and the Nostr Connect exceptions by Step -140. The owning package refactors may remove them earlier. - -## Consequences - -The architecture command fails closed when an ADR is missing, an exception is -expired or broadened, or a new public implementation type appears. Concrete -implementation crates may use third-party types internally, but those types do -not become public API unless the synchronized contract explicitly permits the -package and path. diff --git a/docs/engineering/ci.md b/docs/engineering/ci.md @@ -1,47 +0,0 @@ -# Architecture continuous integration - -The pull-request architecture lane is a thin GitHub adapter over the -repository-owned dispatcher: - -```sh -cargo xtask architecture-ci -``` - -The command validates the synchronized release specification, workspace and -package metadata, production dependency paths, the Cargo-resolved package-tier -graph, public API implementation leakage, SDK feature boundaries, publication -freeze, facade conformance, language contracts, and generated-source freshness. - -Facade conformance pins its exact dependency and feature-forwarding graphs, -curated modules and root exports, absence of new facade-owned traits and -wildcard reexports, explicit ordinary example, and compiled rejection of a -`radroots::sdk` namespace. Clean temporary consumers are executable through -`cargo xtask smoke front-doors-rust-local`. - -SDK feature qualification additionally runs no-default, default, each of the -eleven public features in isolation, the `native` and `full` bundles, and -all-features. Every lane uses `--all-targets`; strict Clippy mirrors the -no-default and all-feature endpoints. Package-boundary tests reject any feature -outside `memory`, `sqlite`, `sync`, `nostr`, `nip46`, `local-signing`, -`radrootsd`, `geonames`, `knowledge`, `native`, and `full`, and verify that -optional dependencies are activated through explicit `dep:` entries. -The workflow invokes the same dispatcher with `cargo run --locked` so lockfile -drift fails rather than being resolved implicitly. - -Until the lower public packages are available from the registry, the checked-in -developer patch configuration requires a coordinated `radrootslabs/lib` -checkout. The workflow pins that public source to -`bb9832fa4c33f68b4262140599c111abb5d5480d`; update the pin only after a -replacement commit is publicly reachable and passes the library architecture -lane. This checkout does not alter any production dependency declaration. - -The workflow grants only read access to repository contents. Action -dependencies are pinned to full commit identifiers. It caches only Cargo -registry and Git downloads, keyed by both repositories' lockfiles and governed -toolchains; generated outputs and build artifacts are never restored from the -cache. - -Repository administrators may require the `Architecture / architecture` -status after the pinned library commit and this workflow commit are publicly -reachable. Changing branch protection or other repository administration -remains a separate authorized operation. diff --git a/docs/engineering/local-overrides.md b/docs/engineering/local-overrides.md @@ -1,16 +0,0 @@ -# Local dependency overrides - -The SDK release manifests resolve packages owned by `radrootslabs/lib` through -their registry identities and exact migration-train versions. Production -`Cargo.toml` files must not contain sibling-repository paths or Git overrides. - -The checked-in `.cargo/config.toml` supplies path patches only for development -inside a coordinated checkout before the initial packages exist in a registry. -Cargo patches do not alter packaged manifests. Package-realistic validation -must run the extracted `.crate` archives outside this repository so the local -configuration cannot satisfy or conceal a registry dependency. - -These patches are temporary migration infrastructure. Remove them once all -lower packages are available to clean consumers from the qualification -registry. Do not add an application, build script, generated package, or public -crate dependency to this override surface. diff --git a/docs/engineering/release-v1-breaking-changes.md b/docs/engineering/release-v1-breaking-changes.md @@ -1,23 +0,0 @@ -# Release V1 breaking changes - -Release V1 establishes two public Rust front doors in the existing `oss/sdk` -repository, both at `0.1.0-alpha`: - -- `radroots` is the curated ordinary-user facade. -- `radroots_sdk` is the advanced host-composition API. - -The release deliberately removes the version-suffixed runtime-contract crate, -the Rust and TypeScript event-index binding packages, SDK-private runtime and -store wrappers, CLI generator ownership, prefixed SDK aliases, and sibling -source consumption. Runtime wire DTOs now come from -`radroots_protocol::runtime::v1`; projection/index behavior comes from -`radroots_storage`; operational listing planning and validation are owned by -`radroots_sdk::listing`. - -See [`sdk-native-api-migration.md`](sdk-native-api-migration.md) for exact Rust -path replacements. There is no compatibility package, deprecated alias, dual -schema, or transitional source path. - -Both public packages are enabled only for package-realistic validation. Actual -crates.io publication remains blocked until the approval packet is complete -and a separate operator action is explicitly authorized. diff --git a/docs/engineering/sdk-lifecycle-test-matrix.md b/docs/engineering/sdk-lifecycle-test-matrix.md @@ -1,19 +0,0 @@ -# SDK lifecycle and safe-default test matrix - -The Release V1 lifecycle contract is qualified at the advanced front door and -at each lower commit boundary. - -| Scenario | Backend/configuration | Evidence | -| --- | --- | --- | -| clean construction starts no network, file, keyring, daemon, runtime, or worker | no-default/default | `lifecycle::clean_default_path_contains_no_implicit_resource_or_worker_authority` and the package-boundary worker guard | -| passive capability reporting | memory | `lifecycle::memory_client_is_passive_clone_shared_and_explicitly_closed` | -| concurrent clone shutdown and idempotent convergence | memory | integration lifecycle test plus `client::tests::concurrent_clones_converge_on_one_closed_state` | -| cancellation before close polling and after close begins | memory | integration lifecycle test plus `client::tests::close_cancellation_boundaries_are_explicit_and_retryable` | -| resources appear only after an explicit open; close is clone-shared | SQLite | `lifecycle::sqlite_resources_exist_only_after_explicit_open_and_close_across_clones` | -| cancellation before atomic enqueue leaves no committed outbox operation | memory canonical sync | farm, listing, and trade enqueue cancellation tests | -| cancellation after atomic enqueue cannot report rollback; replay is idempotent | memory canonical sync | farm, listing, and trade enqueue/replay tests | -| backend status, integrity, and lifecycle stay lower-owned | memory and SQLite | client, storage reliability, diagnostics, and package-boundary tests | - -All resource-producing behavior is tied to an explicit asynchronous method. -Cargo features compile capabilities only; they do not open storage, contact a -transport, load a credential, or install scheduling. diff --git a/docs/engineering/sdk-native-api-migration.md b/docs/engineering/sdk-native-api-migration.md @@ -1,33 +0,0 @@ -# SDK native API migration - -The Release V1 SDK intentionally makes a breaking cut from the predecessor -representation-shaped API. Native Rust callers must use module context, -constructors, builders, and accessors rather than compatibility aliases or -public field layout. - -| Predecessor pattern | Release V1 API | -| --- | --- | -| `RadrootsClient` | `radroots_sdk::Client` | -| `RadrootsClientBuilder` | `radroots_sdk::ClientBuilder` | -| `RadrootsSdkError` | `radroots_sdk::Error` | -| `RadrootsSdk*` or `Sdk*` product wrappers | contextual types such as `farm::Plan`, `listing::PrepareRequest`, and `trade::Operations` | -| SDK copies of event, trade, storage, sync, or transport values | the canonical type from its owning lower crate | -| `radroots_trade::operational_listing::*` | `radroots_sdk::listing::*` for product planning and validation; `radroots_event` retains the canonical public listing model | -| `radroots_runtime_contract_v1::*` | `radroots_protocol::runtime::v1::*` | -| `radroots_event_index` or `@radroots/event-index-bindings` | `radroots_storage::projection::ProjectionStore` and the current protocol/codec-owned generated packages | -| struct literals over SDK request, plan, receipt, status, or error fields | the type's constructor or builder plus stable accessors | - -There are no deprecated prefixed aliases. Code that previously projected SDK -fields directly into Studio or another host must instead translate from stable -accessors at that host boundary. This prevents additive native fields from -causing field-skew failures in consumer struct patterns and keeps private -storage, transport, and signer representations replaceable. - -The crate root exports only `Client`, `ClientBuilder`, `Error`, and `Result`. -Advanced types remain under their owning modules. Deliberately passive, -versioned wire DTOs remain owned by `radroots_protocol`; the SDK does not copy -their public fields into native wrapper structs. - -Step 313 made this cut final: the runtime-contract crate, event-index Rust and -TypeScript packages, CLI generator path, and SDK compatibility shims were -deleted. There is no dual-read, alias, or transitional package path. diff --git a/docs/engineering/sdk-package-conformance.md b/docs/engineering/sdk-package-conformance.md @@ -1,31 +0,0 @@ -# SDK package conformance - -`radroots_sdk` is qualified as a standalone advanced-host package with the -repository-owned checks below. Run every command through the configured build -output router. - -The package matrix contains no-default, default, every public feature in -isolation, `native`, `full`, and all-features, always with all targets. Strict -Clippy covers the no-default and all-feature endpoints. Package tests cover -safe defaults, lifecycle, product planning and commits, native errors, public -API shape, dependency boundaries, and feature law. Rustdoc is checked and -tested with all features. - -The clean-host smoke command is: - -```sh -cargo xtask smoke sdk-rust-local -``` - -It creates a temporary external Cargo application, depends on `radroots_sdk` -through its package path, supplies migration-only local patches for the 17 -lower public packages, and compiles against only the final `ClientBuilder`, -`ErrorKind`, and fail-closed construction surface. It does not rely on a -workspace member, private SDK module, legacy feature, or compatibility alias. -Package-realistic registry and extracted-crate qualification remains owned by -the later release-validation sequence while publication is frozen. - -`cargo xtask architecture-ci` statically validates the same exact feature -vocabulary and activation graph. The public API tests reject SDK-owned host -traits, prefixed native types, public native struct fields, private lower -package dependencies, broad root reexports, and implementation-type leakage. diff --git a/docs/getting-started/rust.md b/docs/getting-started/rust.md @@ -1,10 +0,0 @@ -# Rust getting started - -The primary Rust onboarding contract lives in the packaged -[`radroots` README](../../crates/radroots/README.md). It is included verbatim in -crate rustdoc, so its ordinary memory-client example is compiled as a doctest. - -Advanced host-neutral composition is documented separately in the -[`radroots_sdk` README](../../crates/sdk/README.md). Choose that package only -when the host needs to inject lower storage, signing, transport, or sync -capabilities directly. diff --git a/docs/implementation/COMPATIBILITY_SHIMS.md b/docs/implementation/COMPATIBILITY_SHIMS.md @@ -1,19 +0,0 @@ -# Compatibility shim retirement - -Step 313 removed the final version-suffixed compatibility package after every -standalone consumer cut over to the final protocol and facade surfaces. No -second runtime protocol authority remains. - -| Retired shim | Final owner | Cutover evidence | Final removal | -| --- | --- | --- | --- | -| `radroots_runtime_contract_v1` | `radroots_protocol::runtime::v1` | CLI facade-only refactor and Step 313 source census | Step 313 | - -The SDK consumes `radroots_protocol::runtime::v1` and -`radroots_protocol::radrootsd::transport_publish::v5` directly. Repository -publication policy has no retained compatibility classification, and SDK -code generation no longer owns CLI runtime-contract output. - -Step 248 removed the inactive SDK signer adapter, Nostr adapter, prefixed -models, private store, workflow runtime, and their dormant tests. Step 313 -rejects any returning legacy package, feature, module, generated host surface, -or event-index binding package before release qualification. diff --git a/docs/implementation/DEPENDENCY_RESOLUTION.md b/docs/implementation/DEPENDENCY_RESOLUTION.md @@ -1,23 +0,0 @@ -# Dependency resolution - -This standalone repository owns its `Cargo.lock`. Under `RCRV1-DEV-001`, the -release-v1 refactor does not combine it with the core-library lockfile or make -either repository depend on the other's workspace state. - -Step 017 repaired the stale lock through Cargo's minimal existing-lock -resolution. It added 12 missing transitive package records, added the new -`radroots` workspace package, and refreshed dependency lists without upgrading -existing locked package versions. The resulting checksum is -`422787033afa12d00be7a402f6772bfed194ef420320189b517ca151765eae9c`. - -Step 020 repaired the private preview/test feature boundary by explicitly -enabling `radroots_replica_sync/legacy-ingest` only for the existing wrapper and -SDK development test that consume that gated API. Cargo refreshed only the -local package dependency list; no package version changed. The resulting -checksum is -`246de979d4b2b249182860c4b0adc37fc90c11143c3a279c49201227501d84d9`. -The full locked workspace check, test, Clippy, and rustdoc lanes now pass. - -Dependency changes must use repository-owned extbuild commands, preserve -`--locked` zero-diff validation, and update this evidence when the resolved -graph intentionally changes. diff --git a/docs/implementation/DEVIATIONS.md b/docs/implementation/DEVIATIONS.md @@ -1,53 +0,0 @@ -# Implementation deviations - -The machine-readable authority is [`deviations.toml`](deviations.toml). -Repository checks validate it on every architecture and full check lane. This -ledger records evidence-based changes to implementation planning; it does not -silently change `radroots.crates.release.v1`. - -## Active records - -| ID | Affected steps | Approved disposition | -| --- | --- | --- | -| `RCRV1-DEV-001` | 015-023 | Preserve the existing standalone `lib` and `sdk` repositories; replace repository import/unification with independent qualification. | -| `RCRV1-DEV-005` | 013, 019-026, 226, 247, 249-268, 305 | Pin every Rust crate and internal Radroots dependency in `radrootslabs/sdk` to exactly `0.1.0-alpha` until further explicit authority. | - -## Closed records - -| ID | Closure | -| --- | --- | -| `RCRV1-DEV-002` | The facade remained in `oss/sdk`, completed Steps 249-260, and entered validation-only publication staging at Step 305. | -| `RCRV1-DEV-006` | Steps 261-268 replaced authenticated predecessor snapshots with protocol- and codec-owned generation. | -| `RCRV1-DEV-007` | Step 235 removed SDK-local mappings; Step 313 removed the last daemon/lib transport aliases and helpers. | -| `RCRV1-DEV-008` | Step 313 confirmed every predecessor secrets/storage package and downstream source edge is absent. | -| `RCRV1-DEV-012` | Steps 282-283 qualified the final shared SDK engine, app_rt bindings, and iOS host lifecycle boundary. | - -## Record template - -Add one `[[deviation]]` table to `deviations.toml`: - -```toml -[[deviation]] -id = "RCRV1-DEV-NNN" -date = "YYYY-MM-DD" -status = "active" # active | closed | superseded -approval = "Explicit approving decision." -affected_steps = ["NNN"] -spec_anchors = ["docs/specs/<durable-spec>#<anchor>"] -source_evidence = ["Committed source evidence."] -replacement_action = "Smallest safe disposition." -verification = ["Command or review evidence."] -unresolved_risk = "none, or a concrete bounded risk" -normative_architecture_change = false -adr_required = false -closure_evidence = [] # omit while active; required when closed or superseded -``` - -Every field is mandatory except `closure_evidence` on active records. Spec -anchors must resolve inside `docs/specs/`; affected steps must be three-digit -IDs in 001-315. A normative architecture change needs explicit approval and -the appropriate ADR decision before the record can be accepted. - -Do not silently skip, merge, reorder, or broaden implementation steps. Keep a -red checkpoint uncommitted and mark the next step blocked until its evidence or -approval is complete. diff --git a/docs/implementation/FACADE_SUPERSEDED_SURFACE_AUDIT.md b/docs/implementation/FACADE_SUPERSEDED_SURFACE_AUDIT.md @@ -1,52 +0,0 @@ -# Facade superseded-surface audit - -Step 260 searched every checked-out first-party OSS capsule before the first -`radroots` crate release. No earlier facade crate, facade experiment, public -`radroots::sdk` namespace, or wildcard SDK reexport exists in canonical source. -There is therefore no compatibility package or module to retain, deprecate, or -publish. - -## Canonical SDK capsule - -The only package named `radroots` in this workspace is `crates/radroots`. Its -manifest is enabled only for validation staging after Step 305, its exact -dependency and feature graphs are governed, and its source is limited to the curated -ordinary-user modules. The only advanced engine edge is its private Cargo -dependency on `radroots_sdk`; the facade does not duplicate engine logic. - -The release policy approves only `radroots_sdk` and `radroots` for eventual -package validation. Every other local Cargo package remains private, and the -architecture gate rejects additional publishable identities. No deprecation -placeholder package exists. - -## Other checked-out OSS capsules - -Before its Step 313 cutover, the separate CLI capsule used Cargo package/binary -name `radroots`. That was an application identity, not a facade experiment, -but its Cargo package identity conflicted with the new library front door. -Steps 269-272 migrated the consumer, Step 294 qualified it, and Step 313 -removed the final source branch without introducing a shim. - -The daemon, Apple/mobile, Studio, web, and other checked-out capsules contain -no alternate Rust facade package or `radroots::sdk` namespace. Their real -consumer migrations completed in Steps 269-294. - -`oss/.sdk_step064_worktree` is an untracked local recovery checkout, not a -canonical repository, workspace member, release input, or compatibility -surface. It was intentionally left untouched and excluded from conclusions -about releasable source. - -## Repeatable gate - -From the OSS parent, search canonical capsule source for: - -```sh -rg -n 'radroots[_-](facade|client)|radroots::sdk|pub use radroots_sdk::\*|name = "radroots"' \ - oss --glob 'Cargo.toml' --glob '*.rs' --glob '*.md' --glob '*.toml' -``` - -Then run the SDK capsule's workspace tests and `cargo xtask architecture-ci`. -Expected matches are limited to the final facade, normative specifications and -guards, and clean-smoke fixture names. -Any new package or namespace match blocks release until it is removed or an -explicit later migration step owns it. diff --git a/docs/implementation/HISTORY_PRESERVATION.md b/docs/implementation/HISTORY_PRESERVATION.md @@ -1,26 +0,0 @@ -# Standalone history preservation - -Step 015 is satisfied under `RCRV1-DEV-001` without importing or combining -repository history. This repository remains the independent source authority -for `radroots_sdk`, the new `radroots` facade, bindings, and SDK tooling. - -## Verified checkpoint - -- repository: `git@github.com:radrootslabs/sdk.git` -- reviewed baseline: `fd8384aee348034e0c8ea17a868fe7f094770050` -- verified candidate parent: `7c0177cd5b2261e2e5bea054907aa6147d52aae7` -- baseline relationship: the reviewed baseline is an ancestor of the verified - candidate parent -- submodules: none -- import, subtree, filter-repo, history merge, repository rename, or archive: - not required and not performed - -`git log --follow` retains representative history for -`crates/sdk/Cargo.toml`; `crates/radroots/Cargo.toml` begins at the approved -facade scaffold commit. `git fsck --full` completed successfully with no -corrupt or missing reachable objects. It reported only unreachable dangling -objects retained by Git; those are not part of the release candidate and were -not pruned or modified. - -The next workspace steps must preserve this repository, its lockfile, and its -release boundary independently from `radrootslabs/lib`. diff --git a/docs/implementation/PUBLICATION_FREEZE.md b/docs/implementation/PUBLICATION_FREEZE.md @@ -1,20 +0,0 @@ -# Crates.io publication freeze - -Crates.io upload remains frozen for the complete release-v1 crate refactor. -Step 305 enabled validation metadata for exactly `radroots_sdk` and `radroots`: - -```toml -publish = ["crates-io"] -``` - -`contracts/releases/publication.toml` is the machine authority. `cargo xtask -check` rejects an unexpected registry, package, order, version, or enablement -checkpoint; every other workspace package remains private. - -This validation-only state permits packaging, crates.io dry-runs, and local -ephemeral-registry qualification. It does not authorize upload or any crates.io -mutation. - -Changing the freeze requires an independently reviewed release-control commit. -Actual publication, tag creation, registry ownership changes, and -trusted-publisher changes always require separate explicit authorization. diff --git a/docs/implementation/SDK_SUPERSEDED_SURFACE_AUDIT.md b/docs/implementation/SDK_SUPERSEDED_SURFACE_AUDIT.md @@ -1,55 +0,0 @@ -# SDK superseded-surface audit - -Step 248 closes the predecessor `radroots_sdk` source boundary without adding -a deprecation package or compatibility API. - -## Reachability and manifest audit - -The final crate root reaches only the private `adapters::radrootsd` module and -the eleven chartered public modules. Cargo metadata and the package manifest -register exactly three integration tests and two examples. The removed files -were not reachable from that module graph and were not registered targets -because the package deliberately uses `autotests = false` and `autoexamples = -false`. - -The deletion covers the dormant actor JSON, GeoNames wrapper, idempotency -wrapper, identity/knowledge reexports and builders, privacy model, private SQL -store, product-client wrappers, workflow runtime, obsolete Nostr/signer -adapters, and all tests/support files that exercised only those sources. The -active daemon adapter and its unit tests remain private because the chartered -`transport::DaemonDelivery` implementation uses them. - -The final SDK manifest contains only the nine required and seven optional -Radroots dependencies from the package charter. It has no predecessor private -package dependency, production sibling path, prefixed feature alias, or -unregistered compatibility target. - -## First-party consumer search - -The search covered executable/configuration source in the parent workspace and -all checked-out `oss/*` capsules, excluding historical baselines, handoff -evidence, generated API snapshots, build outputs, and the untracked historical -`.sdk_step064_worktree` recovery checkout. That checkout is not a canonical -repository input and was left untouched. - -The standalone `oss/cli` consumer completed its ordered cutover without a shim: - -- Step 269 removes sibling paths and selects final package/features. -- Step 270 migrates product operations and error imports. -- Step 271 migrates signer and NIP-46 composition. -- Step 272 migrates inbound/outbound synchronization. -- Step 294 proves the complete downstream compatibility matrix. -- Step 313 rejected all remaining legacy public names and source dependencies. - -No other checked-out first-party executable source imports prefixed SDK types. -Documentation, release contracts, architecture fixtures, and lower-package -READMEs that name the final `radroots_sdk` identity are intentional and are not -compatibility consumers. - -## Release disposition - -`radroots_sdk` and `radroots` are enabled only for validation staging through -the sole `crates-io` registry declaration. No deprecation placeholder or -compatibility package exists. Step 313 removed -`radroots_runtime_contract_v1`, the event-index binding crate/package, their -generator paths, and every external legacy consumer. diff --git a/docs/implementation/SDK_WORKSPACE_CONSUMERS.md b/docs/implementation/SDK_WORKSPACE_CONSUMERS.md @@ -1,43 +0,0 @@ -# Rust front-door canonical-workspace consumer cutover - -Step 258 re-audited every Cargo package and Rust source in the standalone SDK -workspace after the final `radroots` facade became active. Cargo metadata has -one front-door dependency edge: - -```text -radroots -> radroots_sdk -``` - -That is the normative engine composition edge. No other workspace package -depends on `radroots` or `radroots_sdk`: - -- binding and WASM packages consume their final owning lower crates; -- `radroots_sdk_sql_wasm_runtime` is a distinct private implementation package, - not a predecessor spelling or an SDK front-door consumer; -- xtask smoke sources construct clean external `radroots` and `radroots_sdk` - hosts and intentionally exercise both public package paths; -- package READMEs and engineering documents use the final identities and do not - create Cargo dependency edges. - -The ordinary example uses only `radroots::client`; the advanced examples use -`radroots_sdk` and explicit lower capability types. There are no application -packages in this capsule to rewrite, no legacy facade package, and no temporary -compatibility dependency to retain. - -CLI, Studio, FFI/mobile, daemon, and other applications are separate repository -capsules. Steps 269-294 migrated and qualified those consumers, and Step 313 -removed their final source-dependency and legacy-name branches. The durable -outcome is recorded in -[`SDK_SUPERSEDED_SURFACE_AUDIT.md`](SDK_SUPERSEDED_SURFACE_AUDIT.md). - -The repeatable audit is: - -```sh -cargo metadata --no-deps --format-version 1 -rg -n 'radroots_sdk|radroots::|radroots =' --glob 'Cargo.toml' --glob '*.rs' -cargo xtask smoke front-doors-rust-local -``` - -The result is a deliberately narrow canonical workspace: ordinary code enters -through `radroots`; advanced host composition enters through `radroots_sdk`; -lower packages and generated bindings do not route through either front door. diff --git a/docs/implementation/STEP_REPORT_TEMPLATE.md b/docs/implementation/STEP_REPORT_TEMPLATE.md @@ -1,58 +0,0 @@ -# Commit-step report template - -Complete this record in the owning rolling-commit document after verification -and before the next handoff step begins. - -```text -Step: -Title: -Repository: -Branch: -Commit SHA: - -Spec anchors: -- ... - -Files changed: -- ... - -Behavior implemented: -- ... - -Tests and verification: -- command: - result: -- command: - result: - -Self-review: -- public API review: -- architecture-boundary review: -- error/secret review: -- feature/target review: -- documentation review: -- generated/lockfile diff review: - -Deviations: -- none -or -- RCRV1-DEV-NNN and evidence - -Unresolved issues: -- none -or -- ... - -Known pre-existing failures: -- none -or -- command, exact failure, evidence, and why it is outside this step - -Next-step safety: -- SAFE / BLOCKED -- reason: -``` - -A step is not complete without its commit SHA, exact command outcomes, -self-review, deviation disposition, and next-step safety decision. A blocked -step does not authorize later work. diff --git a/docs/implementation/TRACEABILITY.md b/docs/implementation/TRACEABILITY.md @@ -1,22 +0,0 @@ -# Release-v1 requirement traceability - -This matrix maps durable architecture requirements to implementation ownership -and verification. It adds no product requirements; the synchronized -`docs/specs/` bundle remains normative. - -| Durable requirement | Owning package or control | Handoff steps | Required evidence | -| --- | --- | --- | --- | -| Exactly 19 public packages with a 17/2 repository split | release policy and architecture catalog | 013, 015-026, 304-305 | Cargo-resolved graph report and exact allowlist validation | -| Every Rust crate remains in the frozen `0.1.0-alpha` cohort | version policy and repository architecture validator | 013, 019-315 | exact workspace package, dependency requirement, lockfile, and synchronized-spec validation | -| Public-only identity and separated signing/secrets | `radroots_identity`, `radroots_signing`, `radroots_secrets` | 052-054, 099-111, 147-155 | public API, feature, dependency, and redaction tests | -| One canonical `TradeId` | `radroots_event`, `radroots_trade` | 073-098 | compile/API inventory and trade conformance | -| Version-neutral protocol ownership | `radroots_protocol` and private generators | 055-064, 261-268 | contract vectors and generated freshness | -| Superseded protocol packages are quarantined and removed | retired compatibility shims | 064, 270, 286 | release classification, source search, and final-removal evidence | -| Independent transport source/sink with extensible identity | `radroots_transport` and adapters | 112-134, 190-207 | transport conformance and forward-compatibility fixtures | -| Storage SPI with SQLite backend | `radroots_storage`, `radroots_storage_sqlite` | 156-189 | backend conformance, migration, recovery, and leakage gates | -| Shared sync engine and explicit lifecycle | `radroots_sync` | 208-225 | pull/push, idempotency, cancellation, and close tests | -| Safe SDK defaults and curated facade | `radroots_sdk`, `radroots` | 226-260 | clean-project package smoke tests and compile-time surface guards | -| Preview and implementation packages remain private | release policy and graph validator | 013, 023-026, 304-305 | private-closure and forbidden-edge fixtures | -| Package-realistic reproducible release | release tooling in both repositories | 295-315 | locked zero-diff package, extracted, local-registry, target, and coverage gates | -| Every first-party consumer migrates | downstream cutover matrix | 269-294 | discovered consumer inventory and canary results | -| Deviations remain explicit and reviewable | `docs/implementation/deviations.toml` | 014 and every affected step | `cargo xtask architecture` plus step report evidence | diff --git a/docs/platform/kotlin.md b/docs/platform/kotlin.md @@ -1,15 +0,0 @@ -# Kotlin SDK FFI bindings - -Kotlin uses the same private `radroots_sdk_ffi` contract as Swift. Generate the -Kotlin/JNA source and `source.lock` from the SDK root with: - -```sh -cargo extbuild run -- cargo xtask generate bindings kotlin -``` - -The repository currently owns no Android or Kotlin build. Accordingly, the -release gate validates deterministic generation, exact source/output hashes, -and the versioned DTO schema inventory only. A future Android host must add its -own JNA/runtime packaging and compile lane; it must not create a parallel -product engine or move keychain, background, scheduling, or presentation -responsibilities into this binding crate. diff --git a/docs/platform/swift.md b/docs/platform/swift.md @@ -1,14 +0,0 @@ -# Swift SDK FFI bindings - -`radroots_sdk_ffi` is the private Rust source of truth. Generate Swift source, -the C header/module map, and `source.lock` from the SDK root with: - -```sh -cargo extbuild run -- cargo xtask generate bindings swift -``` - -The generator builds the FFI library under the extbuild-owned target root, -extracts UniFFI metadata, writes deterministic text artifacts under -`generated/swift`, and binds every output hash to the exact FFI source hash. -Mobile keychain prompts, background execution, scheduling, and presentation -models are deliberately absent and remain owned by the Apple host. diff --git a/docs/specs/README.md b/docs/specs/README.md @@ -1,40 +0,0 @@ -# Release specification index - -This directory carries the coordinated `radroots.crates.release.v1` contract -for the two existing standalone Rust repositories. - -The `radrootslabs/sdk` repository owns packages 18-19, `radroots_sdk` and the -ordinary-user `radroots` facade. The `radrootslabs/lib` repository owns -packages 1-17, from `radroots_core` through `radroots_geonames`. No third Rust -repository is part of this release architecture. - -## Files - -- `radroots_crates_release_v1.md` is the normative architecture and - publication specification. -- `radroots_crates_release_v1.toml` is the machine-readable package, - dependency, feature, and repository-allocation catalog. -- `radroots_crates_release_v1_inventory.csv` is the reviewable package - inventory. -- `radroots_crates_release_v1.dot` is the reviewable dependency and repository - ownership graph. -- `radroots_crates_release_v1.sha256` pins the synchronized contract artifact - contents. - -## Precedence and change control - -Repository instruction files govern how work is performed. Within this -release contract, the Markdown specification is normative, the TOML catalog -is its executable representation, and the CSV and DOT files are review aids. -Current code and tests are implementation evidence, not authority to silently -change the package architecture. - -The four contract artifacts and their hashes MUST match the copies in -`radrootslabs/lib`. A change to package identity, ownership, dependency -direction, or release policy MUST update both repositories together and MUST -fail validation if the copies diverge. - -During migration, package manifests remain non-publishable until their -package-realistic release gates pass. Cross-repository dependencies use -registry versions in release candidates; a sibling checkout is never a -production dependency. diff --git a/docs/specs/radroots_crates_release_v1.md b/docs/specs/radroots_crates_release_v1.md @@ -1,1589 +0,0 @@ -# Radroots Crates Release V1 - -**Normative identifier:** `radroots.crates.release.v1` -**Document status:** Final pressure-tested architecture and publication specification -**Date:** 2026-07-26 -**Coverage amendment:** 2026-07-28 temporary heavy-development baseline -**Source snapshots reviewed:** -- `radrootslabs/lib@466f3cc36739179bc17edb9db796530729ba5219` -- `radrootslabs/sdk@fd8384aee348034e0c8ea17a868fe7f094770050` - -**Repository allocation:** the existing `radrootslabs/lib` and -`radrootslabs/sdk` repositories remain independent. The first 17 packages are -owned by `lib`; `radroots_sdk` and `radroots` are owned by `sdk`. No third Rust -repository is created for release V1. - -**Registry context supplied by the project:** no Radroots crate is currently published on crates.io. Deleted experimental publications create no compatibility, pluralization, deprecation, or version-continuity requirement. - -## 1. Normative language and status - -The words **MUST**, **MUST NOT**, **SHOULD**, **SHOULD NOT**, and **MAY** are normative. - -This specification freezes the **package identities, ownership boundaries, naming model, dependency direction, and release gates** for the first durable Radroots crates.io release. - -It does not claim that the current source tree is already publishable. Publication remains blocked until the refactor is implemented and every acceptance gate in this document passes against packaged artifacts. - -## 2. Final executive decision - -Radroots SHALL publish exactly **19 durable package identities** for release V1: - -1. `radroots_core` -2. `radroots_identity` -3. `radroots_blossom` -4. `radroots_protocol` -5. `radroots_event` -6. `radroots_event_codec` -7. `radroots_trade` -8. `radroots_signing` -9. `radroots_transport` -10. `radroots_nostr` -11. `radroots_nostr_connect` -12. `radroots_secrets` -13. `radroots_storage` -14. `radroots_storage_sqlite` -15. `radroots_transport_nostr` -16. `radroots_sync` -17. `radroots_geonames` -18. `radroots_sdk` -19. `radroots` - -This is neither the current workspace publication list nor a collapse into `radroots_sdk`. - -The package family is implemented across the two existing standalone -repositories. `radrootslabs/lib` owns packages 1-17, and `radrootslabs/sdk` -owns packages 18-19. Cross-repository dependencies resolve through registry -versions; neither repository depends on a sibling checkout. - -The architecture is a layered network/protocol stack: - -```text -portable values / identity / protocol contracts - ↓ -event model and deterministic domain algorithms - ↓ -signing, transport, secrets, and storage SPIs - ↓ -concrete native backends and network adapters - ↓ -local-first synchronization engine - ↓ -advanced SDK - ↓ -ordinary-user façade -``` - -## 3. Final pressure-test changes from the directionally approved draft - -The final review makes the following deliberate changes: - -1. **`radroots_contracts` becomes `radroots_protocol`.** The package is a durable, versioned wire/operation protocol boundary rather than a general-purpose “contracts” bucket. -2. **`radroots_store` and `radroots_store_sqlite` become `radroots_storage` and `radroots_storage_sqlite`.** “Storage” is unambiguous in an agricultural marketplace and describes the package family more accurately than “store.” -3. **`radroots_nostr_connect` remains independent.** It is a bidirectional security protocol with URIs, permissions, client/server state, and independent SDK/Myc consumers. It is not merely a convenience NIP module. -4. **Actor ownership is refined.** Public keys/accounts live in identity; event author roles live in the event contract model; actor provenance, authorization, and signer behavior live in signing. -5. **Trade identity is made singular.** The conflicting `TradeId`/`OrderId` definitions MUST be replaced by one canonical protocol `TradeId` and a separately named business `OrderId`. -6. **Public codegen features are removed.** `dto-bindgen`, binding generation, WASM wrappers, and fixture switches remain private build/test concerns. -7. **The workspace moves to Cargo resolver 3.** A virtual Rust 2024 workspace MUST explicitly set `resolver = "3"`. -8. **Release V1 uses MSRV 1.97.1.** The patch release is selected rather than 1.97.0 because it contains a compiler miscompilation fix. -9. **Lower crates do not remain permanently lockstep.** The current - `radrootslabs/lib` development cohort is frozen at `0.1.0-alpha`, while - `radroots` and `radroots_sdk` remain an exact `0.1.0` lockstep pair. Lower - packages may follow independent SemVer only after explicit future authority - ends the temporary library version freeze. - -## 4. Non-negotiable architecture invariants - -1. Every public package MUST have a durable name and at least one named direct consumer besides `radroots`. -2. Every dependency edge MUST point downward in the architecture. -3. Domain and protocol packages MUST NOT depend on storage, networking, process lifecycle, or host UI. -4. Generic SPIs MUST NOT expose concrete SQLite, Tokio, Reqwest, Nostr SDK, keyring, or OS-specific types. -5. Adapters and backends MUST implement SPIs; SPIs MUST NOT depend on adapters or backends. -6. Synchronization MUST orchestrate sources, sinks, signing, and storage without owning an executor or scheduler. -7. `radroots_sdk` MUST compose lower packages and own client-level commit semantics; it MUST NOT become a dumping ground for code that has an independent durable boundary. -8. `radroots` MUST provide meaningful curation and documentation; it MUST NOT be `pub use radroots_sdk::*`. -9. Version generations MUST live in modules and schema IDs, never in package names. -10. Preview implementation code MAY remain in the monorepo but MUST NOT appear in a published dependency or feature until registry-ready. -11. No public package may have a normal, optional, build, or target-specific dependency on a private Radroots package. -12. No first-party consumer may rely on production sibling paths after cutover. - -## 5. Final public package inventory - -### 5.1 Repository ownership - -- `https://github.com/radrootslabs/lib` owns `radroots_core` through - `radroots_geonames` (packages 1-17). -- `https://github.com/radrootslabs/sdk` owns `radroots_sdk` and `radroots` - (packages 18-19). -- Both repositories retain their existing histories and remain independently - buildable, testable, packageable, and releasable. -- The two repositories carry synchronized copies of this release-family - contract. A coordinated release MUST reject any content-hash or package - allocation mismatch between those copies. - -| Order | Package | Rust crate path | Tier | Permanent responsibility | -|---:|---|---|---|---| -| 1 | `radroots_core` | `radroots_core` | foundation | Foundational value objects and deterministic invariants: decimal, currency, money, percentage, quantity, units, and pricing. | -| 2 | `radroots_identity` | `radroots_identity` | foundation | Public identity and account value types: canonical public keys, identity IDs, account IDs, public profiles, and usernames. | -| 3 | `radroots_blossom` | `radroots_blossom` | protocol primitive | Portable Blossom protocol primitives: canonical blob URLs, hashes, media descriptors, byte-verification typestates, and authorization claims. | -| 4 | `radroots_protocol` | `radroots_protocol` | versioned wire contract | Versioned cross-process and cross-language schemas, capability catalogs, operation descriptors, stable error reports, schema IDs, and structural validation. | -| 5 | `radroots_event` | `radroots_event` | domain protocol model | Canonical Radroots event-domain models, validated event identifiers, tags, event contracts, authoring drafts, signed/verified typestates, and NIP-01 wire-neutral representations. | -| 6 | `radroots_event_codec` | `radroots_event_codec` | deterministic algorithm | Deterministic canonical encoding, decoding, ID/signature verification, contract validation, admission, and manifest generation for Radroots events. | -| 7 | `radroots_trade` | `radroots_trade` | domain algorithm | Trade validation, evidence models, deterministic reduction, conflict analysis, and side-effect-free workflow plans over the canonical event trade model. | -| 8 | `radroots_signing` | `radroots_signing` | host SPI | Object-safe author/signing SPI, actor provenance, authorization checks, requests, receipts, progress, capabilities, and normalized signing errors. | -| 9 | `radroots_transport` | `radroots_transport` | network SPI | Transport-neutral target identities, capability/status models, source and sink SPIs, delivery/fetch policies, bounded requests, provenance, and normalized outcomes. | -| 10 | `radroots_nostr` | `radroots_nostr` | protocol adapter | Portable conversion between Radroots native event/identity types and Nostr protocol types, typed NIP helpers, and concrete local signing adapters; no live relay client. | -| 11 | `radroots_nostr_connect` | `radroots_nostr_connect` | security protocol | Nostr Connect/NIP-46 URIs, methods, permissions, requests, responses, client/server state machines, timeout-independent protocol validation, and normalized errors. | -| 12 | `radroots_secrets` | `radroots_secrets` | security SPI | Secret references, provider and key-wrapping SPIs, versioned encrypted envelopes, zeroization-safe secret handling, and explicit memory/file/keyring adapters. | -| 13 | `radroots_storage` | `radroots_storage` | storage SPI | Backend-neutral canonical event, operation journal, outbox, transport evidence, projection, private-artifact metadata, backup, status, and atomic commit interfaces, plus an in-memory reference backend. | -| 14 | `radroots_storage_sqlite` | `radroots_storage_sqlite` | native storage backend | SQLite implementation of the storage SPIs with schema migration, WAL, locking, integrity, backup/restore, crash recovery, and encrypted private storage. | -| 15 | `radroots_transport_nostr` | `radroots_transport_nostr` | native network adapter | Concrete Nostr EventSource/EventSink implementation: relay URL policy, connection, NIP-42 authentication, bounded fetch pages, delivery, status, and relay-outcome normalization. | -| 16 | `radroots_sync` | `radroots_sync` | local-first orchestration | Shared pull, verification, canonical admission, duplicate handling, projection refresh, outbox signing/delivery, status, and retry-decision orchestration without owning scheduling. | -| 17 | `radroots_geonames` | `radroots_geonames` | concrete data provider | GeoNames asset specification, authenticated/integrity-checked acquisition, database lifecycle, and forward/reverse locality lookup using provider-owned types. | -| 18 | `radroots_sdk` | `radroots_sdk` | advanced front door | Host-neutral asynchronous client engine, product operations, capability reporting, explicit storage/signing/transport composition, diagnostics, backup/restore, and safe commit semantics. | -| 19 | `radroots` | `radroots` | ordinary-user front door | Canonical Rust onboarding package with curated modules, safe defaults, stable convenience builders, domain aggregation, examples, and primary documentation. | - -## 6. Detailed package specifications - - ### 1. `radroots_core` - - **Rust crate path:** `radroots_core` - **Tier:** foundation - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** no_std + alloc; std feature - **Direct intended consumers:** radroots_event, radroots_trade, radroots_sdk, radroots - - **Normative responsibility.** Foundational value objects and deterministic invariants: decimal, currency, money, percentage, quantity, units, and pricing. - - **Required Radroots dependencies:** None - **Optional Radroots dependencies:** None - **Default features:** `std`, `serde` - **Complete public feature vocabulary:** `std`, `serde` - - **Public modules** - - - `currency` -- `decimal` -- `money` -- `percent` -- `pricing` -- `quantity` -- `unit` - - **Permitted root exports:** `Currency`, `Decimal`, `Money`, `Percent`, `Quantity`, `QuantityPrice`, `Unit`, `Error` - - **Explicitly forbidden.** Identifiers, identities, event kinds, networking, persistence, clocks, filesystem paths, process behavior, or application configuration. - - - ### 2. `radroots_identity` - - **Rust crate path:** `radroots_identity` - **Tier:** foundation - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** no_std + alloc; std feature - **Direct intended consumers:** radroots_event, radroots_signing, radroots_transport, radroots_nostr, radroots_nostr_connect, radroots_sdk, services - - **Normative responsibility.** Public identity and account value types: canonical public keys, identity IDs, account IDs, public profiles, and usernames. - - **Required Radroots dependencies:** None - **Optional Radroots dependencies:** None - **Default features:** `std`, `serde` - **Complete public feature vocabulary:** `std`, `serde` - - **Public modules** - - - `account` -- `key` -- `profile` -- `username` - - **Permitted root exports:** `AccountId`, `IdentityId`, `PublicIdentity`, `PublicKey`, `Profile`, `Username`, `Error` - - **Explicitly forbidden.** Secret keys, key generation, NIP-49 encryption, keyrings, files, SQLite, runtime paths, upstream nostr::Event values, signer sessions, or host account selection. - - - ### 3. `radroots_blossom` - - **Rust crate path:** `radroots_blossom` - **Tier:** protocol primitive - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** no_std + alloc; std feature - **Direct intended consumers:** radroots_event, radroots_event_codec, radroots_nostr, media clients - - **Normative responsibility.** Portable Blossom protocol primitives: canonical blob URLs, hashes, media descriptors, byte-verification typestates, and authorization claims. - - **Required Radroots dependencies:** None - **Optional Radroots dependencies:** None - **Default features:** `std`, `serde` - **Complete public feature vocabulary:** `std`, `serde` - - **Public modules** - - - `authorization` -- `descriptor` -- `hash` -- `media_type` -- `url` - - **Permitted root exports:** `BlobUrl`, `Sha256`, `MediaType`, `BlobDescriptor`, `ByteVerifiedDescriptor`, `AuthorizationClaim`, `Error` - - **Explicitly forbidden.** HTTP clients, upload scheduling, cache management, filesystem traversal, application media policy, or global authentication state. - - - ### 4. `radroots_protocol` - - **Rust crate path:** `radroots_protocol` - **Tier:** versioned wire contract - **API maturity at first publish:** durable identity; independently versioned contract modules - **Platform contract:** no_std + alloc; std feature - **Direct intended consumers:** radroots_event, radroots_signing, radroots_transport, radroots_storage, radroots_sync, radroots_sdk, radrootsd, bindings - - **Normative responsibility.** Versioned cross-process and cross-language schemas, capability catalogs, operation descriptors, stable error reports, schema IDs, and structural validation. - - **Required Radroots dependencies:** None - **Optional Radroots dependencies:** None - **Default features:** `std`, `serde` - **Complete public feature vocabulary:** `std`, `serde` - - **Public modules** - - - `capability::v1` -- `error::v1` -- `event::v1` -- `runtime::v1` -- `radrootsd::transport_publish::v5` -- `schema` - - **Permitted root exports:** No broad root exports. - - **Explicitly forbidden.** Native clients, storage, network I/O, executor/runtime ownership, domain reducers, upstream dependency types, unversioned serialized DTOs, or package names containing protocol generations. - - - ### 5. `radroots_event` - - **Rust crate path:** `radroots_event` - **Tier:** domain protocol model - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** no_std + alloc; std feature - **Direct intended consumers:** radroots_event_codec, radroots_trade, radroots_signing, radroots_transport, radroots_storage, radroots_sync, radroots_nostr, radroots_sdk, indexers - - **Normative responsibility.** Canonical Radroots event-domain models, validated event identifiers, tags, event contracts, authoring drafts, signed/verified typestates, and NIP-01 wire-neutral representations. - - **Required Radroots dependencies:** `radroots_core`, `radroots_identity`, `radroots_blossom`, `radroots_protocol` - **Optional Radroots dependencies:** None - **Default features:** `std`, `serde` - **Complete public feature vocabulary:** `std`, `serde`, `knowledge` - - **Public modules** - - - `admission` -- `calendar` -- `contract` -- `draft` -- `envelope` -- `farm` -- `food` -- `id` -- `knowledge` -- `listing` -- `media` -- `post` -- `profile` -- `social` -- `tag` -- `trade` -- `wire` - - **Permitted root exports:** `Event`, `GenericEventDraft`, `SignedEvent`, `VerifiedEvent`, `EventId`, `EventKind`, `EventTag`, `Error` - - **Explicitly forbidden.** Live Nostr clients, relay pools, signing backends, SQLite, outbox claims, retry scheduling, application state, or duplicate trade/order identifier concepts. - - - ### 6. `radroots_event_codec` - - **Rust crate path:** `radroots_event_codec` - **Tier:** deterministic algorithm - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** no_std + alloc where selected features permit; std feature - **Direct intended consumers:** radroots_nostr, radroots_storage_sqlite, radroots_transport_nostr, radroots_sync, radroots_sdk, bindings - - **Normative responsibility.** Deterministic canonical encoding, decoding, ID/signature verification, contract validation, admission, and manifest generation for Radroots events. - - **Required Radroots dependencies:** `radroots_event`, `radroots_blossom`, `radroots_protocol` - **Optional Radroots dependencies:** None - **Default features:** `std`, `json` - **Complete public feature vocabulary:** `std`, `serde`, `json`, `knowledge`, `manifests` - - **Public modules** - - - `admission` -- `canonical` -- `decode` -- `encode` -- `manifest` -- `verify` - - **Permitted root exports:** `Codec`, `DecodeError`, `EncodeError`, `VerificationError` - - **Explicitly forbidden.** nostr-sdk clients, relay networking, persistence, background work, upstream client errors, or host configuration. - - - ### 7. `radroots_trade` - - **Rust crate path:** `radroots_trade` - **Tier:** domain algorithm - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** no_std + alloc for model/reducer; std feature - **Direct intended consumers:** radroots_storage, radroots_sync, radroots_sdk, RHI, applications - - **Normative responsibility.** Trade validation, evidence models, deterministic reduction, conflict analysis, and side-effect-free workflow plans over the canonical event trade model. - - **Required Radroots dependencies:** `radroots_core`, `radroots_identity`, `radroots_event` - **Optional Radroots dependencies:** None - **Default features:** `std`, `serde`, `json` - **Complete public feature vocabulary:** `std`, `serde`, `json` - - **Public modules** - - - `evidence` -- `model` -- `reducer` -- `validation` -- `workflow` - - **Permitted root exports:** `Projection`, `ReductionInput`, `ReducerIssue`, `WorkflowPlan`, `ValidationError`, `Error` - - **Explicitly forbidden.** A second TradeId definition, actor authorization, signers, event-store access, SQLx, filesystem state, transport delivery, outbox mutation, or process scheduling. - - - ### 8. `radroots_signing` - - **Rust crate path:** `radroots_signing` - **Tier:** host SPI - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** no_std + alloc core; std feature - **Direct intended consumers:** radroots_nostr, radroots_sync, radroots_sdk, CLI, Studio, FFI hosts - - **Normative responsibility.** Object-safe author/signing SPI, actor provenance, authorization checks, requests, receipts, progress, capabilities, and normalized signing errors. - - **Required Radroots dependencies:** `radroots_identity`, `radroots_event`, `radroots_protocol` - **Optional Radroots dependencies:** None - **Default features:** `std`, `serde` - **Complete public feature vocabulary:** `std`, `serde` - - **Public modules** - - - `actor` -- `capability` -- `error` -- `request` -- `receipt` -- `signer` -- `status` - - **Permitted root exports:** `Actor`, `Signer`, `SignRequest`, `SignReceipt`, `SignerStatus`, `Error` - - **Explicitly forbidden.** Raw secret-key ownership, keyrings, relay networking, NIP-46 session persistence, SQL, UI prompts, or executor creation. - - - ### 9. `radroots_transport` - - **Rust crate path:** `radroots_transport` - **Tier:** network SPI - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** no_std + alloc data model; std feature - **Direct intended consumers:** radroots_storage, radroots_transport_nostr, radroots_sync, radroots_sdk, services, future adapters - - **Normative responsibility.** Transport-neutral target identities, capability/status models, source and sink SPIs, delivery/fetch policies, bounded requests, provenance, and normalized outcomes. - - **Required Radroots dependencies:** `radroots_identity`, `radroots_event`, `radroots_protocol` - **Optional Radroots dependencies:** None - **Default features:** `std`, `serde` - **Complete public feature vocabulary:** `std`, `serde` - - **Public modules** - - - `capability` -- `endpoint` -- `error` -- `outcome` -- `policy` -- `sink` -- `source` -- `target` - - **Permitted root exports:** `TransportId`, `Target`, `TargetSet`, `EventSource`, `EventSink`, `DeliveryRequest`, `DeliveryReceipt`, `FetchRequest`, `FetchPage`, `Error` - - **Explicitly forbidden.** Closed enums that prevent new transports, Reticulum-specific constants, Nostr URLs at the generic root, storage/outbox access, retries, scheduler ownership, or silent fallback. - - - ### 10. `radroots_nostr` - - **Rust crate path:** `radroots_nostr` - **Tier:** protocol adapter - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** no_std + alloc for conversion surface; std feature - **Direct intended consumers:** radroots_nostr_connect, radroots_transport_nostr, radroots_sdk, Myc, radrootsd - - **Normative responsibility.** Portable conversion between Radroots native event/identity types and Nostr protocol types, typed NIP helpers, and concrete local signing adapters; no live relay client. - - **Required Radroots dependencies:** `radroots_identity`, `radroots_event`, `radroots_event_codec` - **Optional Radroots dependencies:** `radroots_signing`, `radroots_blossom` - **Default features:** `std`, `events` - **Complete public feature vocabulary:** `std`, `events`, `signing`, `nip17`, `blossom` - - **Public modules** - - - `blossom` -- `event` -- `filter` -- `key` -- `nip17` -- `signing` -- `tag` - - **Permitted root exports:** `Error` - - **Explicitly forbidden.** nostr-sdk relay pools, reqwest clients, runtime ownership, broad aliases of upstream nostr types at the root, account persistence, or outbox orchestration. - - - ### 11. `radroots_nostr_connect` - - **Rust crate path:** `radroots_nostr_connect` - **Tier:** security protocol - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** std for v1; protocol data kept portable - **Direct intended consumers:** radroots_sdk, Myc, remote signer tooling - - **Normative responsibility.** Nostr Connect/NIP-46 URIs, methods, permissions, requests, responses, client/server state machines, timeout-independent protocol validation, and normalized errors. - - **Required Radroots dependencies:** `radroots_identity`, `radroots_event`, `radroots_nostr`, `radroots_protocol` - **Optional Radroots dependencies:** None - **Default features:** `serde` - **Complete public feature vocabulary:** `serde` - - **Public modules** - - - `client` -- `error` -- `message` -- `method` -- `permission` -- `server` -- `uri` - - **Permitted root exports:** `Client`, `Server`, `Method`, `Permission`, `Request`, `Response`, `BunkerUri`, `ClientUri`, `Error` - - **Explicitly forbidden.** Relay-pool implementation, secret persistence, approval UI, global sessions, Tokio runtime ownership, or Myc-specific service storage. - - - ### 12. `radroots_secrets` - - **Rust crate path:** `radroots_secrets` - **Tier:** security SPI - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** no_std + alloc core; std adapters - **Direct intended consumers:** radroots_storage_sqlite, radroots_sdk, signing hosts, services - - **Normative responsibility.** Secret references, provider and key-wrapping SPIs, versioned encrypted envelopes, zeroization-safe secret handling, and explicit memory/file/keyring adapters. - - **Required Radroots dependencies:** None - **Optional Radroots dependencies:** None - **Default features:** `std`, `serde` - **Complete public feature vocabulary:** `std`, `serde`, `memory`, `file`, `keyring` - - **Public modules** - - - `envelope` -- `error` -- `id` -- `provider` -- `wrapping` -- `memory` -- `file` -- `keyring` - - **Permitted root exports:** `SecretId`, `SecretRef`, `SecretProvider`, `KeyWrapping`, `EncryptedEnvelope`, `Error` - - **Explicitly forbidden.** Public secret bytes, Clone/Debug/Serialize for secret-bearing values, identity profiles, domain tables, arbitrary key/value storage, hidden key generation, or process-global vaults. - - - ### 13. `radroots_storage` - - **Rust crate path:** `radroots_storage` - **Tier:** storage SPI - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** std for v1 - **Direct intended consumers:** radroots_storage_sqlite, radroots_sync, radroots_sdk, indexers, tests, future backends - - **Normative responsibility.** Backend-neutral canonical event, operation journal, outbox, transport evidence, projection, private-artifact metadata, backup, status, and atomic commit interfaces, plus an in-memory reference backend. - - **Required Radroots dependencies:** `radroots_event`, `radroots_trade`, `radroots_transport`, `radroots_protocol` - **Optional Radroots dependencies:** None - **Default features:** `memory`, `serde` - **Complete public feature vocabulary:** `memory`, `serde` - - **Public modules** - - - `atomic` -- `backup` -- `event` -- `journal` -- `memory` -- `outbox` -- `private_artifact` -- `projection` -- `status` - - **Permitted root exports:** `Storage`, `EventStore`, `Journal`, `Outbox`, `ProjectionStore`, `BackupSource`, `StorageStatus`, `Error` - - **Explicitly forbidden.** SQL text, SQLx pools or transactions, filesystem paths, application UI state, concrete retry loops, Nostr clients, or unconstrained raw key/value escape hatches. - - - ### 14. `radroots_storage_sqlite` - - **Rust crate path:** `radroots_storage_sqlite` - **Tier:** native storage backend - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** std-only native backend - **Direct intended consumers:** radroots_sdk, CLI, Studio, mobile/FFI - - **Normative responsibility.** SQLite implementation of the storage SPIs with schema migration, WAL, locking, integrity, backup/restore, crash recovery, and encrypted private storage. - - **Required Radroots dependencies:** `radroots_storage`, `radroots_event_codec`, `radroots_secrets` - **Optional Radroots dependencies:** None - **Default features:** None - **Complete public feature vocabulary:** None - - **Public modules** - - - `backup` -- `config` -- `integrity` -- `lock` -- `migration` -- `open` -- `status` - - **Permitted root exports:** `SqliteStorage`, `OpenOptions`, `OpenMode`, `Paths`, `Error` - - **Explicitly forbidden.** Public SqlitePool/Connection/Transaction handles, caller-supplied arbitrary SQL, Studio state, global connection pools, runtime installation, or silent schema downgrade. - - - ### 15. `radroots_transport_nostr` - - **Rust crate path:** `radroots_transport_nostr` - **Tier:** native network adapter - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** std-only; Tokio implementation detail in v1 - **Direct intended consumers:** radroots_sdk, CLI, radrootsd, advanced hosts - - **Normative responsibility.** Concrete Nostr EventSource/EventSink implementation: relay URL policy, connection, NIP-42 authentication, bounded fetch pages, delivery, status, and relay-outcome normalization. - - **Required Radroots dependencies:** `radroots_transport`, `radroots_nostr`, `radroots_event_codec`, `radroots_protocol` - **Optional Radroots dependencies:** None - **Default features:** None - **Complete public feature vocabulary:** None - - **Public modules** - - - `auth` -- `client` -- `relay` -- `sink` -- `source` -- `status` - - **Permitted root exports:** `NostrTransport`, `Config`, `RelayUrl`, `RelayUrlPolicy`, `Error` - - **Explicitly forbidden.** Event-store ingestion, outbox claiming, retry scheduling, projection refresh, global relay clients, direct SQL, or transport fallback. - - - ### 16. `radroots_sync` - - **Rust crate path:** `radroots_sync` - **Tier:** local-first orchestration - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** std-only in v1; executor-neutral public API - **Direct intended consumers:** radroots_sdk, CLI, Studio, mobile/FFI, advanced hosts - - **Normative responsibility.** Shared pull, verification, canonical admission, duplicate handling, projection refresh, outbox signing/delivery, status, and retry-decision orchestration without owning scheduling. - - **Required Radroots dependencies:** `radroots_event`, `radroots_event_codec`, `radroots_signing`, `radroots_transport`, `radroots_storage`, `radroots_trade`, `radroots_protocol` - **Optional Radroots dependencies:** None - **Default features:** `serde` - **Complete public feature vocabulary:** `serde` - - **Public modules** - - - `ingest` -- `policy` -- `projection` -- `pull` -- `push` -- `status` - - **Permitted root exports:** `Engine`, `PullRequest`, `PullReceipt`, `PushRequest`, `PushPreparation`, `PushStatus`, `SigningRunReceipt`, `AdmissionRunReceipt`, `DeliveryExecutionReceipt`, `SyncStatus`, `Error` - - **Explicitly forbidden.** Creating an executor, spawning hidden workers, installing timers globally, owning process lifecycle, storing UI state, or transport-specific branches outside adapters. - - - ### 17. `radroots_geonames` - - **Rust crate path:** `radroots_geonames` - **Tier:** concrete data provider - **API maturity at first publish:** durable identity; pre-1.0 API - **Platform contract:** std-only - **Direct intended consumers:** radroots_sdk, CLI, geocoding applications - - **Normative responsibility.** GeoNames asset specification, authenticated/integrity-checked acquisition, database lifecycle, and forward/reverse locality lookup using provider-owned types. - - **Required Radroots dependencies:** None - **Optional Radroots dependencies:** None - **Default features:** None - **Complete public feature vocabulary:** None - - **Public modules** - - - `asset` -- `database` -- `download` -- `model` -- `query` - - **Permitted root exports:** `Geocoder`, `AssetSpec`, `AssetStatus`, `Query`, `Candidate`, `Point`, `Error` - - **Explicitly forbidden.** Generic multi-provider abstraction before a second provider exists, runtime-path policy, hidden downloads, SDK configuration types, SQLx/reqwest types in the public API, or test-fixture features. - - - ### 18. `radroots_sdk` - - **Rust crate path:** `radroots_sdk` - **Tier:** advanced front door - **API maturity at first publish:** durable identity; lockstep pre-1.0 API with radroots - **Platform contract:** std-only native engine - **Direct intended consumers:** CLI, Studio, FFI/mobile, advanced native applications - - **Normative responsibility.** Host-neutral asynchronous client engine, product operations, capability reporting, explicit storage/signing/transport composition, diagnostics, backup/restore, and safe commit semantics. - - **Required Radroots dependencies:** `radroots_core`, `radroots_identity`, `radroots_protocol`, `radroots_event`, `radroots_event_codec`, `radroots_trade`, `radroots_signing`, `radroots_transport`, `radroots_storage` - **Optional Radroots dependencies:** `radroots_secrets`, `radroots_storage_sqlite`, `radroots_nostr`, `radroots_nostr_connect`, `radroots_transport_nostr`, `radroots_sync`, `radroots_geonames` - **Default features:** `memory` - **Complete public feature vocabulary:** `memory`, `sqlite`, `sync`, `nostr`, `nip46`, `local-signing`, `radrootsd`, `geonames`, `knowledge`, `native`, `full` - - **Public modules** - - - `capability` -- `client` -- `diagnostics` -- `error` -- `farm` -- `listing` -- `signing` -- `storage` -- `sync` -- `trade` -- `transport` - - **Permitted root exports:** `Client`, `ClientBuilder`, `Error`, `Result` - - **Explicitly forbidden.** Global runtimes or subscribers, hidden workers, process signals, CLI parsing, UI state, Studio databases, raw SQLx/upstream client types, broad wildcard reexports, or a nominal no_std claim. - - - ### 19. `radroots` - - **Rust crate path:** `radroots` - **Tier:** ordinary-user front door - **API maturity at first publish:** durable identity; lockstep pre-1.0 API with radroots_sdk - **Platform contract:** std-only - **Direct intended consumers:** ordinary Rust applications, examples, documentation - - **Normative responsibility.** Canonical Rust onboarding package with curated modules, safe defaults, stable convenience builders, domain aggregation, examples, and primary documentation. - - **Required Radroots dependencies:** `radroots_sdk`, `radroots_core`, `radroots_identity`, `radroots_event`, `radroots_trade`, `radroots_transport` - **Optional Radroots dependencies:** None - **Default features:** `client` - **Complete public feature vocabulary:** `client`, `native`, `nostr`, `nip46`, `radrootsd`, `geonames`, `knowledge`, `full` - - **Public modules** - - - `client` -- `event` -- `farm` -- `identity` -- `knowledge` -- `listing` -- `signing` -- `storage` -- `sync` -- `trade` -- `transport` - - **Permitted root exports:** `Client`, `ClientBuilder`, `Error`, `Result` - - **Explicitly forbidden.** A public radroots::sdk namespace, wildcard reexport of radroots_sdk, duplicate engine implementation, CLI binary, hidden network/filesystem/keychain side effects, or exposure of every lower-crate symbol. - - -## 7. Normative dependency graph - -### 7.1 Direct Radroots edges - -| Dependency | Dependent | Edge | -|---|---|---| -| `radroots_blossom` | `radroots_event` | required | -| `radroots_core` | `radroots_event` | required | -| `radroots_identity` | `radroots_event` | required | -| `radroots_protocol` | `radroots_event` | required | -| `radroots_blossom` | `radroots_event_codec` | required | -| `radroots_event` | `radroots_event_codec` | required | -| `radroots_protocol` | `radroots_event_codec` | required | -| `radroots_core` | `radroots_trade` | required | -| `radroots_event` | `radroots_trade` | required | -| `radroots_identity` | `radroots_trade` | required | -| `radroots_event` | `radroots_signing` | required | -| `radroots_identity` | `radroots_signing` | required | -| `radroots_protocol` | `radroots_signing` | required | -| `radroots_event` | `radroots_transport` | required | -| `radroots_identity` | `radroots_transport` | required | -| `radroots_protocol` | `radroots_transport` | required | -| `radroots_blossom` | `radroots_nostr` | optional | -| `radroots_signing` | `radroots_nostr` | optional | -| `radroots_event` | `radroots_nostr` | required | -| `radroots_event_codec` | `radroots_nostr` | required | -| `radroots_identity` | `radroots_nostr` | required | -| `radroots_event` | `radroots_nostr_connect` | required | -| `radroots_identity` | `radroots_nostr_connect` | required | -| `radroots_nostr` | `radroots_nostr_connect` | required | -| `radroots_protocol` | `radroots_nostr_connect` | required | -| `radroots_event` | `radroots_storage` | required | -| `radroots_protocol` | `radroots_storage` | required | -| `radroots_trade` | `radroots_storage` | required | -| `radroots_transport` | `radroots_storage` | required | -| `radroots_event_codec` | `radroots_storage_sqlite` | required | -| `radroots_secrets` | `radroots_storage_sqlite` | required | -| `radroots_storage` | `radroots_storage_sqlite` | required | -| `radroots_event_codec` | `radroots_transport_nostr` | required | -| `radroots_nostr` | `radroots_transport_nostr` | required | -| `radroots_protocol` | `radroots_transport_nostr` | required | -| `radroots_transport` | `radroots_transport_nostr` | required | -| `radroots_event` | `radroots_sync` | required | -| `radroots_event_codec` | `radroots_sync` | required | -| `radroots_protocol` | `radroots_sync` | required | -| `radroots_signing` | `radroots_sync` | required | -| `radroots_storage` | `radroots_sync` | required | -| `radroots_trade` | `radroots_sync` | required | -| `radroots_transport` | `radroots_sync` | required | -| `radroots_geonames` | `radroots_sdk` | optional | -| `radroots_nostr` | `radroots_sdk` | optional | -| `radroots_nostr_connect` | `radroots_sdk` | optional | -| `radroots_secrets` | `radroots_sdk` | optional | -| `radroots_storage_sqlite` | `radroots_sdk` | optional | -| `radroots_sync` | `radroots_sdk` | optional | -| `radroots_transport_nostr` | `radroots_sdk` | optional | -| `radroots_core` | `radroots_sdk` | required | -| `radroots_event` | `radroots_sdk` | required | -| `radroots_event_codec` | `radroots_sdk` | required | -| `radroots_identity` | `radroots_sdk` | required | -| `radroots_protocol` | `radroots_sdk` | required | -| `radroots_signing` | `radroots_sdk` | required | -| `radroots_storage` | `radroots_sdk` | required | -| `radroots_trade` | `radroots_sdk` | required | -| `radroots_transport` | `radroots_sdk` | required | -| `radroots_core` | `radroots` | required | -| `radroots_event` | `radroots` | required | -| `radroots_identity` | `radroots` | required | -| `radroots_sdk` | `radroots` | required | -| `radroots_trade` | `radroots` | required | -| `radroots_transport` | `radroots` | required | - -### 7.2 Architectural graph - -```text -radroots_core radroots_identity radroots_blossom - \ | / - \ | / - +---------- radroots_protocol --------+ - | - radroots_event - / | \ - / | \ - radroots_event_codec | radroots_trade - | - +----------+-----------+ - | | | - radroots_signing radroots_transport radroots_storage - | | | - | radroots_nostr +--> radroots_storage_sqlite - | | - | radroots_nostr_connect - | | - +---- radroots_transport_nostr - | - radroots_sync - -radroots_geonames -------------------------+ - | -all selected lower packages ----------> radroots_sdk ---> radroots -``` - -This diagram is explanatory. The release tool MUST use Cargo-resolved metadata as authority. - -## 8. Type ownership and canonical paths - -| Concept | Canonical owning crate | Rule | -|---|---|---| -| Decimal, money, quantity, unit, pricing | `radroots_core` | No duplicate wrapper in SDK or trade. | -| Public key, identity ID, account ID, username | `radroots_identity` | Secret material is forbidden here. | -| Event ID, event signature, coordinate, D-tag, event kind | `radroots_event` | Store bytes/newtypes, not unvalidated Strings. | -| Event contract author role | `radroots_event::contract` | This is an event-authoring rule, not an account property. | -| Actor provenance and author context | `radroots_signing` | Combines identity with event author roles at the signing boundary. | -| Canonical protocol TradeId/CandidateId/MutationId | `radroots_event::trade` | Exactly one definition. | -| Human/business OrderId | `radroots_trade` | MUST NOT be aliased or wrapped as TradeId. | -| Runtime/wire DTO generations | `radroots_protocol` | Native packages convert at boundaries. | -| Secret references and encrypted envelopes | `radroots_secrets` | No domain-specific tables. | -| Transport ID, target, capability, outcome | `radroots_transport` | TransportId is extensible, not a closed enum. | -| Native event/outbox/journal/projection storage | `radroots_storage` | Backend-neutral interfaces only. | -| SQLite schema and connection behavior | `radroots_storage_sqlite` | SQLx remains private. | -| Relay URL and Nostr network status | `radroots_transport_nostr` | Protocol conversions remain in `radroots_nostr`. | -| Pull/push/ingest/projection orchestration | `radroots_sync` | No host scheduling. | -| Client-level requests, plans, receipts, diagnostics | `radroots_sdk` | Use lower canonical types rather than duplicate wrappers. | - -## 9. Rust API and naming law - -### 9.1 Packages, crates, modules, and types - -- Cargo package names MUST use lowercase snake case: `radroots_event_codec`. -- Rust crate paths MUST use the same lowercase snake case: `radroots_event_codec`. -- Modules MUST use singular snake-case nouns unless the concept is inherently plural. -- Types and traits MUST use `UpperCamelCase`; functions and methods MUST use `snake_case`. -- Items MUST NOT repeat their crate or module name: - - `radroots_core::Money`, not `RadrootsCoreMoney`. - - `radroots_sdk::Error`, not `RadrootsSdkError`. - - `radroots_transport::Target`, not `RadrootsTransportTarget`. -- Protocol schema IDs retain the `radroots.*` namespace. -- Generated Swift/Kotlin types MAY retain a `Radroots` prefix where the target language lacks module-level namespacing. - -### 9.2 Public surface discipline - -- Crate roots MUST be small. -- Wildcard reexports and `pub use models::*` are forbidden. -- Lower crates MUST NOT publish a broad `prelude` in V1. -- Every native public struct MUST have private fields unless it is an intentionally passive versioned DTO in `radroots_protocol`. -- Evolvable enums and reports SHOULD be `#[non_exhaustive]`. -- Semantic IDs MUST NOT implement `Deref<Target = str>`. -- IDs SHOULD store canonical bytes or validated compact representations; string encoding belongs at boundaries. -- Use `FromStr`, `TryFrom`, `AsRef`, `Display`, and explicit `into_string`/`to_hex` methods. -- No root-level aliases to upstream `nostr`, `nostr_sdk`, `sqlx`, `reqwest`, `tokio`, or keyring types. -- Public functions MUST NOT panic for untrusted input. -- Builders/plans/receipts SHOULD be `#[must_use]`. -- Constructors with more than three independent options SHOULD use builders or option structs. -- Empty request structs are forbidden when an idiomatic no-argument method conveys the same operation. - -### 9.3 Trait classification - -Every public trait MUST be marked in documentation as one of: - -1. **Host SPI** — downstream implementation is supported. -2. **Sealed extension** — downstream calls are supported; implementation is not. -3. **Internal** — not public. - -Host SPIs MUST: - -- be dyn-compatible where runtime injection is needed; -- be `Send + Sync` for the native SDK; -- return boxed futures or equivalent dyn-compatible futures; -- define cancellation and deadline behavior; -- define error normalization; -- avoid associated types that leak backend implementations; -- not expose private or third-party implementation types. - -The Rust SPI is native. Browser and generated-language transports use `radroots_protocol` DTOs and language-native interfaces rather than weakening native `Send + Sync` guarantees. - -## 10. Feature law - -1. Features MUST be additive and safe under unification. -2. Features MUST describe user-visible capabilities, not implementation assembly. -3. Optional dependencies MUST be referenced with `dep:` so implementation names do not become accidental features. -4. Default features MUST remain safe for the life of a compatible release line. -5. Enabling a feature MUST NOT itself: - - access a network; - - create files; - - read a keyring; - - generate keys; - - contact a daemon; - - install logging; - - start workers. -6. Mutually exclusive backend features are forbidden; incompatible backends belong in separate packages. -7. Public crates MUST NOT expose `dto-bindgen`, fixtures, coverage, codegen, migration-forge, or internal runtime features. -8. `std` is the only valid feature name for standard-library support. -9. Public feature removal is a breaking change. -10. `--all-features` MUST build on every declared target for which the package claims support. - -### 10.1 `radroots_sdk` - -```toml -[features] -default = ["memory"] - -# Safe, in-process storage; no files or network. -memory = ["radroots_storage/memory"] - -# Explicit native capabilities. -sqlite = ["dep:radroots_storage_sqlite"] -sync = ["dep:radroots_sync", "dep:uuid"] -nostr = [ - "sync", - "dep:radroots_nostr", - "dep:radroots_transport_nostr", -] -nip46 = [ - "nostr", - "dep:radroots_nostr_connect", -] -local-signing = [ - "dep:radroots_secrets", - "radroots_nostr/signing", -] -radrootsd = [ - "sync", - "dep:reqwest", -] -geonames = ["dep:radroots_geonames"] -knowledge = [ - "radroots_event/knowledge", - "radroots_event_codec/knowledge", -] - -native = ["sqlite", "sync", "local-signing"] -full = [ - "native", - "nostr", - "nip46", - "radrootsd", - "geonames", - "knowledge", -] -``` - -### 10.2 `radroots` - -```toml -[features] -default = ["client"] - -client = ["radroots_sdk/default"] -native = ["client", "radroots_sdk/native"] -nostr = ["client", "radroots_sdk/nostr"] -nip46 = ["nostr", "radroots_sdk/nip46"] -radrootsd = ["client", "radroots_sdk/radrootsd"] -geonames = ["client", "radroots_sdk/geonames"] -knowledge = ["client", "radroots_sdk/knowledge"] -full = ["radroots_sdk/full"] -``` - -Reticulum, mesh, Simplex, NostrDB, replica, and SP1 feature names MUST NOT appear in published V1 manifests. - -## 11. Network and transport SPI - -### 11.1 Separate source and sink contracts - -One monolithic transport trait is rejected. The final SPI provides independent contracts: - -```rust -pub trait EventSource: Send + Sync { - fn status(&self) -> BoxFuture<'_, Result<SourceStatus, Error>>; - fn fetch(&self, request: FetchRequest) - -> BoxFuture<'_, Result<FetchPage, Error>>; -} - -pub trait EventSink: Send + Sync { - fn status(&self) -> BoxFuture<'_, Result<SinkStatus, Error>>; - fn deliver(&self, request: DeliveryRequest) - -> BoxFuture<'_, Result<DeliveryReceipt, Error>>; -} -``` - -A transport MAY implement either or both. - -### 11.2 Extensible transport identity - -`TransportId` MUST be a validated newtype with built-in constants such as `NOSTR`, `RETICULUM`, `LOCAL`, and `RADROOTSD`. It MUST NOT be a closed enum that forces a breaking release for every new transport. - -### 11.3 Bounded and explicit operation semantics - -- Fetch is paginated or streaming and always bounded. -- Every request carries an operation/request ID. -- Deadlines are explicit; no adapter owns a global timeout. -- Delivery satisfaction policy is explicit. -- Partial success is represented per target. -- Retryability is data, not an implicit loop. -- Authentication challenges are explicit outcomes. -- No transport silently falls back to another. -- Provenance records source, endpoint fingerprint, observed time, and adapter. -- Adapter errors are normalized while preserving a non-secret source chain. -- Target URIs and relay URLs are validated before connection. -- SSRF-sensitive schemes and private-network policies are explicit. -- TLS verification is enabled by default and cannot be silently disabled. -- Payload, target, tag, response, and page limits are constants covered by tests. - -## 12. Storage architecture - -### 12.1 Logical ownership - -`radroots_storage` owns interfaces for: - -- canonical event admission and queries; -- operation journal; -- outbox and delivery evidence; -- projection checkpoints and invalidation; -- private-artifact metadata; -- backup/restore contracts; -- storage status and integrity; -- atomic workflow commits. - -`radroots_storage_sqlite` implements them. - -### 12.2 Native layout - -The SQLite V1 layout SHALL use: - -```text -runtime.sqlite - canonical event source - event admission/visibility - operation journal - outbox and delivery evidence - projection metadata and checkpoints - -private.sqlite - encrypted signing references - private farm coordinates - private trade artifacts - NIP-46 private session material where host policy permits - -host-owned databases - UI preferences - Studio state - application presentation caches -``` - -`studio.sqlite` is removed from the SDK. - -### 12.3 Correctness requirements - -- One runtime database permits atomic event/journal/outbox transitions. -- Cross-database workflows use explicit staged commits and recovery markers. -- Public API exposes high-level atomic operations, not raw SQL transactions. -- No public `pool()` escape hatch. -- Open modes: read-only, read-write-existing, create. -- Explicit asynchronous `close()` and shutdown status. -- Advisory/process locking is mandatory for writable file stores. -- Concurrent readers are supported; writer policy is explicit. -- Migrations are transactional and forward-only by default. -- Downgrade requires an explicit offline export/import path. -- WAL and busy timeout are configured and reported. -- Backup uses a versioned manifest, per-member hashes, path/symlink validation, and atomic finalization. -- Restore uses staging, verification, and atomic replacement. -- Crash/failure injection covers every durable commit point. -- Secret material inclusion in backup is explicit and policy-controlled. - -## 13. Identity, signing, and secret boundaries - -### 13.1 Identity - -`radroots_identity` contains no private key and no upstream Nostr event object. `PublicKey` is a validated canonical Radroots author key. NIP-19/npub conversion lives in `radroots_nostr`. - -### 13.2 Signing - -`radroots_signing::Signer` signs an immutable canonical `AuthoredEventPlan`. The signing layer: - -- authorizes actor role and expected public key before invoking a signer; -- verifies the signer result matches the exact draft; -- supports local and remote implementations; -- exposes capability and progress data; -- defines cancellation before and after remote request publication; -- never logs or serializes private material. - -Concrete local Nostr signing lives in `radroots_nostr`; NIP-46 protocol state lives in `radroots_nostr_connect`; host composition lives in `radroots_sdk`. - -### 13.3 Secrets - -Secret-bearing values: - -- MUST NOT implement ordinary `Debug`; -- MUST NOT implement `Serialize`; -- MUST NOT implement `Clone` unless the clone is a reference/handle; -- MUST zeroize owned plaintext where technically possible; -- MUST expose only redacted diagnostics; -- MUST use typed `SecretRef` handles across storage boundaries. - -## 14. Event and trade model corrections - -1. `radroots_event` remains the canonical owner of event-bound identifiers and trade wire identities. -2. `radroots_trade` MUST delete its conflicting `TradeId(OrderId)` definition. -3. `TradeId` and `OrderId` MUST remain semantically distinct. -4. `radroots_trade` consumes canonical event trade models and owns reducers, evidence, validation, and workflow plans. -5. Trade MUST NOT depend on authority, storage, SQLx, Nostr clients, or transports. -6. Event codec MUST own wire conversion; trade reducers operate on validated native inputs. -7. Typed authoring policy MUST reject reserved event kinds before any signer is consulted. -8. Native event typestates distinguish raw, ID-verified, signature-verified, contract-validated, admitted, and visible events. - -## 15. Error model - -Each crate owns a native `Error` with preserved sources. `radroots_protocol::error::v1::ErrorReport` is the serialized boundary. - -One generated authority MUST define: - -- stable code; -- class; -- retryability; -- recovery actions; -- capability ID; -- operation ID; -- safe structured details; -- redaction behavior. - -Hand-maintained duplicate match tables and a separate unsynchronized catalog are forbidden. - -Third-party errors MUST NOT appear as public variants. Sensitive source messages MUST be redacted before entering a protocol report or tracing field. - -## 16. SDK and façade rules - -### 16.1 `radroots_sdk` - -- `Client` is `Clone + Send + Sync`. -- The host owns the executor and scheduling. -- The SDK starts no unbounded or hidden worker. -- Background processing requires an explicit returned worker/driver handle. -- Dropping a future before/after commit has documented effects. -- `Client::close()` is explicit and asynchronous where storage is active. -- Product writes retain prepare → authorize/sign → durable enqueue → optional deliver semantics. -- Lower canonical types are reused rather than copied into `Sdk*` wrappers. -- No `RadrootsSdk*` prefixes inside the crate. -- Root exports are only `Client`, `ClientBuilder`, `Error`, and `Result`. - -### 16.2 `radroots` - -- Primary documentation and examples use `radroots`. -- The façade adds curated modules, convenience constructors, safe defaults, and domain aggregation. -- Advanced hosts use `radroots_sdk` directly. -- There is no `radroots::sdk` public namespace. -- The façade does not expose implementation crates accidentally. - -## 17. Public code generation and cross-language policy - -- Rust binding, WASM, UniFFI, Swift, Kotlin, TypeScript, and codegen crates remain `publish = false`. -- Public runtime crates have no codegen feature or codegen dependency. -- Versioned language DTOs derive from `radroots_protocol`. -- Deterministic event algorithms derive from `radroots_event_codec`. -- Generated artifacts are checked in or generated reproducibly and carry source hashes. -- Rust native module structure is not mechanically mirrored into other languages. -- Language runtimes own networking, scheduling, keychain prompts, and UI lifecycle where appropriate. - -## 18. Private and deferred packages - -The following remain private in release V1: - -```text -replica schema/store/sync family -Reticulum adapter -mesh protocol/agent/client family -SimpleX protocol/crypto/store/runtime family -NostrDB adapter -SP1 guest/host -runtime paths/manager/distribution helpers -radrootsd SDK adapter implementation -FFI, binding, WASM, and generated-package build crates -fixtures, conformance runners, fuzz targets, and xtask -``` - -Private preview code remains tested. It may become public only after passing the new-package admission rule. - -## 19. New-package admission rule - -After release V1, a new `radroots_*` package requires an ADR proving: - -1. a durable domain/protocol/SPI/backend boundary; -2. at least two meaningful direct consumers, or one unavoidable platform/backend isolation boundary; -3. an independently supportable SemVer surface; -4. a publishable resolved dependency closure; -5. a name expected to survive five years; -6. why a module or feature is insufficient; -7. documentation, conformance tests, ownership, security review, and release automation. - -Names containing `common`, `utils`, `types`, `models`, `preview`, `unstable`, `v1`, `v2`, `manager`, or a second `core` are presumptively rejected. - -## 20. Current-to-target migration map - -| Current package/family | Final owner | Required action | -|---|---|---| -| `radroots_core` | `radroots_core` | Retain the snake-case package name and remove RadrootsCore type prefixes. | -| `radroots_identity` | `radroots_identity + radroots_signing + radroots_secrets + radroots_storage` | Keep only public identity/account concepts in identity; move secrets, signers, and persistence. | -| `radroots_blossom` | `radroots_blossom` | Retain portable protocol primitives. | -| `radroots_protocol_contract_v1` | `radroots_protocol::event::v1 / capability::v1` | Retired, non-publishable compatibility package after merge; final removal at Step 270 after the CLI cutover. | -| `radroots_runtime_contract_v1` | `radroots_protocol::runtime::v1` | Retired, non-publishable SDK compatibility package after merge; final removal at Step 270 after the CLI cutover. | -| `radroots_transport_publish_protocol` | `radroots_protocol::radrootsd::transport_publish::v5` | Retired, non-publishable compatibility package after merge; final removal at Step 286 after the radrootsd cutover. | -| `radroots_event` | `radroots_event` | Retain singular package; narrow to canonical event-domain model. | -| `radroots_event_codec` | `radroots_event_codec` | Retain; remove live Nostr/upstream client responsibilities. | -| `radroots_event_index` | `radroots_storage::projection/index` | Merge; current checkpoint/manifest model is not an independent indexing engine. | -| `radroots_trade` | `radroots_trade` | Retain algorithms; remove authority, storage, SQL, transport, and duplicate TradeId. | -| `radroots_authority` | `radroots_identity + radroots_event::contract + radroots_signing` | Split account/public-key ownership, author-role contracts, and signing/authorization SPI. | -| `radroots_transport` | `radroots_transport` | Retain and redesign as extensible source/sink SPI. | -| `radroots_transport_nostr` | `radroots_transport_nostr` | Retain adapter; remove storage and sync orchestration. | -| `radroots_transport_reticulum` | `private preview` | Withhold until a real adapter passes the transport conformance suite. | -| `radroots_nostr` | `radroots_nostr` | Retain protocol conversion; remove live relay client and broad upstream aliases. | -| `radroots_nostr_connect` | `radroots_nostr_connect` | Retain as independent bidirectional NIP-46 protocol boundary. | -| `radroots_nostr_accounts` | `radroots_identity + radroots_secrets + radroots_storage + radroots_sdk` | Split mixed account, vault, persistence, and manager responsibilities. | -| `radroots_nostr_signer` | `radroots_signing + radroots_nostr_connect + Myc-private state` | Do not publish current service-state package. | -| `radroots_nostr_runtime` | `radroots_transport_nostr + radroots_sync` | Merge live relay runtime into adapter/orchestration layers. | -| `radroots_nostrdb` | `private; possible future radroots_storage_nostrdb` | Withhold until the storage SPI and external consumers justify a backend package. | -| `radroots_event_store` | `radroots_storage + radroots_storage_sqlite` | Split backend-neutral contracts from SQLite implementation. | -| `radroots_outbox` | `radroots_storage + radroots_storage_sqlite` | Merge as one persistence capability with atomic operation commits. | -| `radroots_runtime_store` | `radroots_storage or host-private state` | Retire broad name and classify each table by owner. | -| `radroots_sql_core` | `radroots_storage_sqlite private internals` | Remove raw SQL/JSON executor from public API. | -| `radroots_secret_vault` | `radroots_secrets` | Merge provider/wrapping SPI. | -| `radroots_protected_store` | `radroots_secrets` | Merge encrypted-envelope semantics. | -| `radroots_geocoder` | `radroots_geonames` | Rename to the actual concrete provider. | -| `radroots_runtime` | `radroots_sync + radroots_storage + host-private tooling` | Dismantle mixed config/signals/logging/queue/transport package. | -| `radroots_log` | `no replacement package` | Libraries emit tracing; hosts install subscribers. | -| `radroots_net` | `radroots_transport + radroots_sync + radroots_sdk` | Retire broad duplicated network/runtime package. | -| `radroots_runtime_paths` | `private host utility` | Do not place host path policy in the SDK registry closure. | -| `radroots_runtime_manager` | `private host tooling` | Runtime installation and process lifecycle remain host-owned. | -| `radroots_runtime_distribution` | `private host tooling` | Artifact distribution is not a public SDK dependency. | -| `radroots_replica_*` | `private/deferred` | Preserve and redesign; no public names until generated CRUD/raw SQL surfaces are replaced. | -| `radroots_mesh_*` | `private preview` | Preserve; publish only a real adapter or protocol with external consumers. | -| `radroots_simplex_*` | `private preview` | Preserve internal decomposition; no crates.io commitment in release v1. | -| `radroots_trade_sp1_*` | `private build/preview` | Keep specialized guest/host packages private. | -| `binding, WASM, FFI, codegen, fixtures, xtask` | `private build/test packages` | Publish generated language artifacts, not Rust build machinery. | - -## 21. Workspace and manifest policy - -```toml -[workspace] -resolver = "3" - -[workspace.package] -edition = "2024" -rust-version = "1.97.1" -license = "MIT OR Apache-2.0" -homepage = "https://radroots.org" -``` - -Each standalone workspace sets its own repository metadata: - -```toml -# radrootslabs/lib -[workspace.package] -repository = "https://github.com/radrootslabs/lib" -``` - -```toml -# radrootslabs/sdk -[workspace.package] -repository = "https://github.com/radrootslabs/sdk" -``` - -Every public package MUST define: - -```toml -[package] -name = "radroots_..." -version = "<repository-governed exact version>" -publish = ["crates-io"] -edition.workspace = true -rust-version.workspace = true -license.workspace = true -repository.workspace = true -homepage.workspace = true -readme = "README.md" -documentation = "https://docs.rs/radroots_..." -``` - -Additional rules: - -- Use an explicit `include` whitelist. -- Include both license files. -- Every same-repository public dependency uses `path + version`. -- Every dependency from `radrootslabs/sdk` to a package owned by - `radrootslabs/lib` uses a registry version and MUST NOT use a sibling path or - Git override in a release candidate. -- No Git dependency exists in a published normal/build/target/optional closure. -- Public packages avoid build scripts; generated source is checked and freshness-tested. -- Workspace lints forbid unsafe code by default. -- Public API crates deny broken rustdoc links. -- Package metadata lists only accurate keywords/categories. -- docs.rs metadata selects an intentional feature set instead of blindly enabling platform-incompatible features. - -## 22. Versioning and release policy - -### 22.1 Initial versions - -Every Rust crate in `radrootslabs/lib`, including private build, test, preview, -and support crates, is pinned to exactly `0.1.0-alpha`. Every same-repository -dependency requirement is pinned to exactly `=0.1.0-alpha`. This temporary -cohort is frozen until an explicit future authority changes it; neither normal -development nor release preparation may bump it implicitly. - -Every Rust crate in `radrootslabs/sdk`, including bindings, WASM wrappers, -runtime contracts, build tools, `radroots_sdk`, and `radroots`, is likewise -pinned to exactly `0.1.0-alpha`; every internal Radroots dependency uses the -exact `=0.1.0-alpha` requirement. Cross-repository dependencies use that same -frozen cohort without creating a path dependency between the standalone -repositories. This document's “V1” is the architecture specification version, -not a claim that Rust APIs are already 1.0-stable. - -Cargo package versions are independent from versioned wire, conformance, -database, and operation contracts. Changing the library crate cohort MUST NOT -rewrite authenticated historical protocol artifacts or derive Cargo SemVer -from a protocol contract version. - -### 22.2 SemVer groups - -- `radroots` and `radroots_sdk` release in lockstep and `radroots` uses `=X.Y.Z` for the SDK. -- Lower packages version independently after the first release. -- Lower dependencies use ordinary compatible requirements at the actual minimum supported version. -- Exact requirements are reserved for genuinely inseparable package pairs. -- Wire/event/runtime/storage/backup/generated-schema versions are independent of Cargo package versions. -- Every package gets its own changelog section and public API baseline. -- The repository maintains a tested compatibility manifest for the current SDK release. - -### 22.3 Breaking changes before 1.0 - -For `0.y.z` packages: - -- breaking API changes increment `y`; -- compatible fixes/features increment `z`; -- package names and responsibility charters remain permanent; -- moving a public type between packages is breaking and requires an ADR; -- first-party consumers migrate in the same coordinated cutover. - -## 23. Indicative publication order - -The actual order is computed from `cargo metadata`; the expected order is: - -```text -radroots_core -radroots_identity -radroots_blossom -radroots_protocol -radroots_secrets -radroots_geonames -radroots_event -radroots_event_codec -radroots_trade -radroots_signing -radroots_transport -radroots_nostr -radroots_nostr_connect -radroots_storage -radroots_storage_sqlite -radroots_transport_nostr -radroots_sync -radroots_sdk -radroots -``` - -Actual publication waits for each dependency to appear in the crates.io index before publishing dependents. - -## 24. Required CI and release gates - -### 24.1 Workspace - -- `cargo fmt --all -- --check` -- `cargo check --workspace --all-targets` -- `cargo clippy --workspace --all-targets --all-features -- -D warnings` -- `cargo test --workspace --all-targets` -- `cargo doc --workspace --no-deps` -- doctests -- generated-output freshness -- protocol/contract/conformance validation -- forbidden identifier and dependency checks - -### 24.2 Feature/target matrix - -For every public package: - -- no default features; -- default features; -- each public feature independently; -- supported feature bundles; -- all features; -- MSRV 1.97.1; -- current stable; -- Linux, macOS, Windows; -- declared no_std target; -- `wasm32-unknown-unknown` where supported; -- native package targets; -- minimal and latest compatible dependencies. - -### 24.3 Public API - -- `cargo-semver-checks`; -- public API baseline; -- rustdoc with warnings denied; -- no undocumented public item exceptions without review; -- examples compile from packaged artifacts; -- no duplicate canonical type paths except deliberate façade reexports; -- no third-party type leakage in generic packages. - -### 24.4 Reliability and security - -- fuzz event, protocol, NIP-46, URL, manifest, backup, and restore parsers; -- malformed and oversized network payloads; -- cancellation before and after commit; -- idempotency replay and conflict; -- outbox claim expiry; -- partial delivery and retry; -- signer timeout/wrong response/auth challenge; -- storage multi-reader/writer/locking; -- migration and corruption failure; -- crash recovery at every commit point; -- backup/restore interruption, traversal, symlink, and hash mismatch; -- projection invalidation/rebuild; -- secret redaction; -- dependency audit, license policy, provenance, SBOM, and advisory checks. - -### 24.5 Coverage policy - -During the active heavy-development refactor, every required workspace crate -owned by `radrootslabs/lib` MUST maintain at least 90% executable-line, -function, region, and branch coverage. Branch measurement remains required -except for a machine-recorded temporary exception where the coverage tool -emits no branch records. Crate-specific numeric thresholds below 90% are -forbidden. The -machine-readable authority for the active gate is `contracts/coverage.toml` in -`radrootslabs/lib`. - -This amendment does not alter the independently governed `radrootslabs/sdk` -coverage contract. The 90% baseline is temporary development policy, not -permission to remove meaningful tests or weaken package-specific conformance -requirements. The 100% threshold is deferred until this refactor stabilizes -and may be reinstated only through an explicit future contract and -specification update. - -### 24.6 Package-realistic release validation - -For every public package: - -1. Resolve the graph with `cargo metadata`. -2. Reject all public-to-private edges across normal, optional, build, target, and reachable-feature dependencies. -3. Run `cargo package --locked`. -4. Inspect the normalized manifest. -5. Inspect `cargo package --list`. -6. Extract the `.crate`. -7. Build, test, and document the extracted package. -8. Run `cargo publish --dry-run --locked`. -9. Publish to an ephemeral/local registry. -10. Build clean external projects against registry artifacts. -11. Build CLI, Studio, FFI/mobile, web packages, services, and indexers against package artifacts. -12. Confirm no sibling path or Git override remains. - -## 25. Source-evidence record - -| Repository | Reviewed SHA | Source | Pressure-test finding | -|---|---|---|---| -| `radrootslabs/lib` | `466f3cc36739179bc17edb9db796530729ba5219` | `Cargo.toml` | Workspace currently contains 49+ packages, uses edition 2024 with resolver 2, and centralizes underscore-named path dependencies. | -| `radrootslabs/lib` | `466f3cc36739179bc17edb9db796530729ba5219` | `contracts/releases/publish_policy.toml` | Current public classification contains broad runtime/storage/tooling crates while SDK-required packages remain internal. | -| `radrootslabs/sdk` | `fd8384aee348034e0c8ea17a868fe7f094770050` | `crates/sdk/Cargo.toml` | SDK feature graph names implementation assembly and directly references private authority, event-store, outbox, transport, and adapter crates. | -| `radrootslabs/lib` | `466f3cc36739179bc17edb9db796530729ba5219` | `crates/authority/src/{actor,authorization,signer}.rs` | Current authority package combines account provenance, event contract roles, signing SPI, authorization, and concrete local signing. | -| `radrootslabs/lib` | `466f3cc36739179bc17edb9db796530729ba5219` | `crates/event/src/ids.rs` | Semantic identifiers are stored as Strings, implement Deref<str>, and include trade/account/network concepts in one module. | -| `radrootslabs/lib` | `466f3cc36739179bc17edb9db796530729ba5219` | `crates/trade/src/identity.rs` | A second TradeId wraps OrderId, conflicting with the canonical event TradeId concept. | -| `radrootslabs/lib` | `466f3cc36739179bc17edb9db796530729ba5219` | `crates/identity/src/identity.rs` | Identity owns raw secret keys, upstream Nostr event values, file formats, generation, and secret export methods. | -| `radrootslabs/lib` | `466f3cc36739179bc17edb9db796530729ba5219` | `crates/transport/src/{kind,transport}.rs` | TransportKind is a closed enum and one monolithic trait requires both fetch and deliver. | -| `radrootslabs/lib` | `466f3cc36739179bc17edb9db796530729ba5219` | `crates/transport_nostr/{Cargo.toml,src/lib.rs}` | Nostr adapter currently couples relay transport to event-store and outbox persistence. | -| `radrootslabs/lib` | `466f3cc36739179bc17edb9db796530729ba5219` | `crates/event_store/src/store.rs and crates/outbox/src/store.rs` | Concrete stores expose SQLx pools/transactions and split related runtime state across separately opened stores. | -| `radrootslabs/lib` | `466f3cc36739179bc17edb9db796530729ba5219` | `crates/runtime/src/lib.rs and crates/log/src/init.rs` | Runtime package combines host concerns; logging installs process-global subscriber state. | -| `radrootslabs/sdk` | `fd8384aee348034e0c8ea17a868fe7f094770050` | `crates/sdk/src/{lib,runtime,studio_store,error}.rs` | SDK root broadly reexports implementation-shaped types, owns studio.sqlite, exposes many public fields, and duplicates error metadata. | - -## 26. Rejected alternatives - -### Publish the current public list - -Rejected because it permanently exposes host tooling and still omits SDK-required private dependencies. - -### Publish every current dependency unchanged - -Rejected because temporary implementation boundaries would become permanent package identities. - -### Collapse lower crates into `radroots_sdk` - -Rejected because domain, protocol, SPI, backend, and adapter packages have independent consumers and semver responsibilities. - -### One `radroots_runtime` package - -Rejected because runtime configuration, process lifecycle, paths, logging, queues, storage, and networking are not one coherent library boundary. - -### Separate packages for every domain or NIP - -Rejected because it creates package proliferation. Only independently substantial protocols with direct consumers—such as Nostr Connect—receive a package. - -### Versioned package names - -Rejected. Versions belong in modules and schema IDs. - -### Public preview placeholder packages - -Rejected. Preview code remains private until the implementation is real and conformance-tested. - -### Public codegen features - -Rejected. Code generation is a private build concern and must not enlarge the runtime registry closure. - -## 27. Cutover sequence - -1. Freeze publication and record this specification as an ADR. -2. Preserve the independent `radrootslabs/lib` and `radrootslabs/sdk` - histories; record the 17/2 package allocation and synchronized contract - hashes without forming or importing a third repository. -3. Switch workspace to resolver 3 and MSRV 1.97.1. -4. Create final snake-case package manifests with `publish = false` during migration. -5. Refactor identity/public-key ownership and remove all secret material. -6. Split authority among identity, event contracts, and signing. -7. Remove the duplicate TradeId and make trade algorithm-only. -8. Create `radroots_protocol`. -9. Create `radroots_secrets`. -10. Create `radroots_storage` and `radroots_storage_sqlite`; migrate event/outbox/journal/private storage. -11. Remove Studio state from SDK storage. -12. Redesign `radroots_transport`; separate source/sink. -13. Narrow `radroots_nostr` and `radroots_transport_nostr`. -14. Refactor and retain `radroots_nostr_connect`. -15. Create `radroots_sync`. -16. Rename/refocus GeoNames. -17. Refactor SDK root, features, errors, lifecycle, and commit semantics. -18. Add the curated `radroots` façade. -19. Migrate every first-party consumer. -20. Run package-realistic validation. -21. Change only the 19 final packages to `publish = ["crates-io"]`. -22. Publish in Cargo-derived order after explicit authorization. - -## 28. Completion and publication decision - -The package identities and boundaries in this specification are final for release V1. - -Publication is authorized only when all of the following are simultaneously true: - -- all 19 packages implement their charters; -- no forbidden responsibility remains; -- Cargo-resolved closure contains only public Radroots packages; -- all feature/target/package/downstream gates pass; -- naming availability and ownership are confirmed; -- current-source licensing and contributor provenance are cleared; -- generated cross-language contracts are coherent; -- no first-party host remains on legacy or sibling-path APIs; -- the actual `.crate` archives have been inspected and tested. - -Until then, the correct status is: - -```text -Architecture: FINAL -Implementation: REQUIRED -Publication: BLOCKED -``` - -## 29. Final reaffirmation - -This is the final recommended Radroots crates surface. - -It preserves real modularity without turning every current workspace folder into a permanent public package. It establishes stable identities for foundational values, identity, event protocol, trade algorithms, signing, transport, secrets, storage, Nostr, synchronization, a concrete geodata provider, the advanced SDK, and the ordinary-user façade. - -It intentionally withholds host utilities, preview transports, generated CRUD/replica code, experimental messaging/proof systems, codegen, FFI machinery, and test support. - -No additional public crate is required for release V1, and no package in the 19-package family is present merely to satisfy Cargo. Each has a durable responsibility, named consumers, a one-way dependency position, and a credible independent SemVer surface. diff --git a/package.json b/package.json @@ -3,6 +3,7 @@ "private": true, "packageManager": "pnpm@10.25.0", "scripts": { + "contracts:check": "node tools/radroots_sdk_contract.mjs", "source:check": "node tools/radroots_sdk_artifact.mjs source-check", "generate:ts": "node tools/radroots_sdk_artifact.mjs write typescript", "generate:wasm": "node tools/radroots_sdk_artifact.mjs write wasm", @@ -11,7 +12,7 @@ "generate": "pnpm run generate:ts && pnpm run generate:wasm && pnpm run generate:swift && pnpm run generate:kotlin", "check:generated": "node tools/radroots_sdk_artifact.mjs check typescript && node tools/radroots_sdk_artifact.mjs check wasm && node tools/radroots_sdk_artifact.mjs check swift && node tools/radroots_sdk_artifact.mjs check kotlin", "test:tools": "node --test tools/*.test.mjs", - "check": "pnpm run generate && pnpm -r build && pnpm -r typecheck && pnpm run test:tools && pnpm run check:generated", + "check": "pnpm run contracts:check && pnpm run generate && pnpm -r build && pnpm -r typecheck && pnpm run test:tools && pnpm run check:generated", "build": "pnpm run generate:ts && pnpm run generate:wasm && pnpm -r build", "typecheck": "pnpm -r typecheck" }, diff --git a/tools/radroots_sdk_contract.mjs b/tools/radroots_sdk_contract.mjs @@ -0,0 +1,10 @@ +#!/usr/bin/env node + +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +import { validateHistoricalAuthority } from "./radroots_sdk_contract_lib.mjs"; + +const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +validateHistoricalAuthority(root); +process.stdout.write("SDK contracts: OK\n"); diff --git a/tools/radroots_sdk_contract.test.mjs b/tools/radroots_sdk_contract.test.mjs @@ -0,0 +1,85 @@ +import assert from "node:assert/strict"; +import { createHash } from "node:crypto"; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + writeFileSync, +} from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import test from "node:test"; + +import { + HISTORICAL_ARTIFACTS, + HISTORICAL_AUTHORITY_PATH, + validateHistoricalAuthority, +} from "./radroots_sdk_contract_lib.mjs"; + +const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); + +function fixture() { + const target = mkdtempSync(join(tmpdir(), "radroots-sdk-contract-")); + for (const relative of [ + HISTORICAL_AUTHORITY_PATH, + ...HISTORICAL_ARTIFACTS.map((artifact) => artifact.path), + ]) { + const destination = join(target, relative); + mkdirSync(dirname(destination), { recursive: true }); + copyFileSync(join(root, relative), destination); + } + return target; +} + +test("checked-in historical authority is exact", () => { + assert.doesNotThrow(() => validateHistoricalAuthority(root)); +}); + +test("historical authority rejects artifact drift", () => { + const target = fixture(); + const artifact = HISTORICAL_ARTIFACTS[0].path; + writeFileSync(join(target, artifact), "tampered\n"); + assert.throws( + () => validateHistoricalAuthority(target), + /artifact digest mismatch/, + ); +}); + +test("historical authority rejects coordinated artifact and manifest drift", () => { + const target = fixture(); + const artifact = HISTORICAL_ARTIFACTS[0].path; + const replacement = "coordinated tamper\n"; + writeFileSync(join(target, artifact), replacement); + const path = join(target, HISTORICAL_AUTHORITY_PATH); + const manifest = JSON.parse(readFileSync(path, "utf8")); + manifest.artifacts[0].sha256 = createHash("sha256") + .update(replacement) + .digest("hex"); + writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\n`); + assert.throws( + () => validateHistoricalAuthority(target), + /artifact 0 identity is invalid/, + ); +}); + +test("historical authority rejects unknown manifest fields", () => { + const target = fixture(); + const path = join(target, HISTORICAL_AUTHORITY_PATH); + const manifest = JSON.parse(readFileSync(path, "utf8")); + manifest.unreviewed = true; + writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\n`); + assert.throws(() => validateHistoricalAuthority(target), /invalid keys/); +}); + +test("historical authority rejects public documentation and workflows", () => { + for (const forbidden of ["docs", ".github", ".act"]) { + const target = fixture(); + mkdirSync(join(target, forbidden)); + assert.throws( + () => validateHistoricalAuthority(target), + { message: `forbidden capsule root exists: ${forbidden}` }, + ); + } +}); diff --git a/tools/radroots_sdk_contract_lib.mjs b/tools/radroots_sdk_contract_lib.mjs @@ -0,0 +1,201 @@ +import { createHash } from "node:crypto"; +import { lstatSync, readFileSync } from "node:fs"; +import { resolve } from "node:path"; + +export const HISTORICAL_AUTHORITY_PATH = + "contracts/historical_authority.v1.json"; + +export const HISTORICAL_ARTIFACTS = Object.freeze([ + Object.freeze({ + path: "contracts/api_baselines/radroots-0.1.0-alpha.txt", + role: "public_api_baseline", + sha256: "e0c21fc096715fba3b3273bb1a8a880d6e871161772c5a1019404064aa0becb1", + }), + Object.freeze({ + path: "contracts/api_baselines/radroots_sdk-0.1.0-alpha.txt", + role: "public_api_baseline", + sha256: "97dfccb393fcc7953a59f0b12f03485daf9b7c625e9a4529fd883fcf0306e618", + }), + Object.freeze({ + path: "contracts/architecture/deviations.toml", + role: "historical_deviation_ledger", + sha256: "888d581264cddf6fe0b4a09a2171535094ef9fb3c422f7866e4e0c802359ea1f", + }), + Object.freeze({ + path: "contracts/crates/release_v1/radroots_crates_release_v1.dot", + role: "historical_release_graph", + sha256: "d47de10be596a4d33fee102a4f0617f66700b49515a75a1f42d62c9710043059", + }), + Object.freeze({ + path: "contracts/crates/release_v1/radroots_crates_release_v1.sha256", + role: "captured_stale_checksum_manifest", + sha256: "5759ceaae30a9435346320c2791cfda9eb1559b779ea79fd2e94810e14efa281", + }), + Object.freeze({ + path: "contracts/crates/release_v1/radroots_crates_release_v1.toml", + role: "historical_release_catalog", + sha256: "1dc18437200dcd65b52090493306f452dade89b5116401d71be4ba4127239b19", + }), + Object.freeze({ + path: "contracts/crates/release_v1/radroots_crates_release_v1_inventory.csv", + role: "historical_release_inventory", + sha256: "5020875c2cda4b2c9568c8b3f0fad5cd96756c3c779a72481a9652e558f77891", + }), +]); + +const RETIRED_HUMAN_ARTIFACTS = Object.freeze([ + Object.freeze({ + former_path: + "docs/decisions/0001-public-api-leakage-migration-baseline.md", + parent_path: + "docs/oss/sdk/release-v1-history/decisions/0001-public-api-leakage-migration-baseline.md", + sha256: "c5f2367bc85c84ce5a3af0d066d3fc8dab6d4e9f1061bb6af35b15d9e4b6e2b1", + }), + Object.freeze({ + former_path: "docs/specs/radroots_crates_release_v1.md", + parent_path: + "docs/oss/sdk/release-v1-history/release-v1-specification.md", + sha256: "6f98eb958a29921919147c44ff6a80565df367adf362f7ac872ce2588a09a1e5", + }), +]); + +const CAPTURED_CHECKSUM_MANIFEST = + "5a11c6ad90cf03162ca2ce4d1692192d01fa57a31c03fd07d61f70093da5e703 radroots_crates_release_v1.md\n" + + "7db533f32c70306b29adea35f85686e67287ae33abd33d1013a61590449f1296 radroots_crates_release_v1.toml\n" + + "5020875c2cda4b2c9568c8b3f0fad5cd96756c3c779a72481a9652e558f77891 radroots_crates_release_v1_inventory.csv\n" + + "d47de10be596a4d33fee102a4f0617f66700b49515a75a1f42d62c9710043059 radroots_crates_release_v1.dot\n"; + +function exactKeys(value, expected, context) { + if (!value || typeof value !== "object" || Array.isArray(value)) { + throw new Error(`${context} must be an object`); + } + const actual = Object.keys(value).sort(); + const wanted = [...expected].sort(); + if (JSON.stringify(actual) !== JSON.stringify(wanted)) { + throw new Error(`${context} has invalid keys`); + } +} + +function regularFile(path, context) { + let metadata; + try { + metadata = lstatSync(path); + } catch (error) { + throw new Error(`${context} is missing: ${error.code ?? error.message}`); + } + if (!metadata.isFile() || metadata.isSymbolicLink()) { + throw new Error(`${context} must be a regular non-symlink file`); + } +} + +function pathExists(path) { + try { + lstatSync(path); + return true; + } catch (error) { + if (error.code === "ENOENT") { + return false; + } + throw error; + } +} + +function sha256(path) { + return createHash("sha256").update(readFileSync(path)).digest("hex"); +} + +export function validateHistoricalAuthority(root) { + for (const forbidden of ["docs", ".github", ".act"]) { + if (pathExists(resolve(root, forbidden))) { + throw new Error(`forbidden capsule root exists: ${forbidden}`); + } + } + + const manifestPath = resolve(root, HISTORICAL_AUTHORITY_PATH); + regularFile(manifestPath, HISTORICAL_AUTHORITY_PATH); + const manifest = JSON.parse(readFileSync(manifestPath, "utf8")); + exactKeys( + manifest, + [ + "schema_version", + "contract_id", + "status", + "source_revision", + "parent_human_owner", + "capsule_human_docs_forbidden", + "artifacts", + "retired_human_artifacts", + "captured_checksum_manifest", + ], + "historical authority", + ); + if ( + manifest.schema_version !== 1 || + manifest.contract_id !== "radroots.sdk.historical_authority.v1" || + manifest.status !== "historical" || + manifest.source_revision !== + "bcda74b3ebfff3f711670cc25b7910f27360fba7" || + manifest.parent_human_owner !== "docs/oss/sdk/release-v1-history" || + manifest.capsule_human_docs_forbidden !== true + ) { + throw new Error("historical authority identity is invalid"); + } + + if ( + !Array.isArray(manifest.artifacts) || + manifest.artifacts.length !== HISTORICAL_ARTIFACTS.length + ) { + throw new Error("historical artifact inventory is not exact"); + } + for (let index = 0; index < HISTORICAL_ARTIFACTS.length; index += 1) { + const artifact = manifest.artifacts[index]; + const expected = HISTORICAL_ARTIFACTS[index]; + exactKeys(artifact, ["path", "role", "sha256"], `artifact ${index}`); + if ( + artifact.path !== expected.path || + artifact.role !== expected.role || + artifact.sha256 !== expected.sha256 + ) { + throw new Error(`artifact ${index} identity is invalid`); + } + if (!/^[0-9a-f]{64}$/.test(artifact.sha256)) { + throw new Error(`artifact ${index} digest is invalid`); + } + const artifactPath = resolve(root, artifact.path); + regularFile(artifactPath, artifact.path); + if (sha256(artifactPath) !== artifact.sha256) { + throw new Error(`artifact digest mismatch: ${artifact.path}`); + } + } + + if ( + JSON.stringify(manifest.retired_human_artifacts) !== + JSON.stringify(RETIRED_HUMAN_ARTIFACTS) + ) { + throw new Error("retired human artifact inventory is not exact"); + } + + exactKeys( + manifest.captured_checksum_manifest, + ["path", "status", "current_digest_authority"], + "captured checksum manifest", + ); + if ( + manifest.captured_checksum_manifest.path !== + "contracts/crates/release_v1/radroots_crates_release_v1.sha256" || + manifest.captured_checksum_manifest.status !== + "historical_stale_capture" || + manifest.captured_checksum_manifest.current_digest_authority !== + HISTORICAL_AUTHORITY_PATH + ) { + throw new Error("captured checksum disposition is invalid"); + } + if ( + readFileSync( + resolve(root, manifest.captured_checksum_manifest.path), + "utf8", + ) !== CAPTURED_CHECKSUM_MANIFEST + ) { + throw new Error("captured stale checksum manifest changed"); + } +}