README (36463B)
1 # mycorrhiza 2 3 This is the README for `myc` which provides a Nostr remote signer for 4 standalone and application-embedded clients. 5 6 ## Public API boundary 7 8 The library exposes one curated crate-root API. All implementation modules are 9 private, and public errors use Myc-owned stable classifications with redacted 10 diagnostics and no raw dependency-owned source chain. The shared runtime-path, 11 service-SQLite, and storage identity values that appear in signatures are 12 intentional governed contract types; raw SQLx, provider, transport, Serde, and 13 task authority never crosses this boundary. 14 15 The runtime foundation is sealed and cannot be forged or reached through a 16 child module: 17 18 ```compile_fail 19 use myc::runtime_foundation::MycRuntimeFoundation; 20 21 fn forge(_: MycRuntimeFoundation) {} 22 ``` 23 24 The reviewed all-features surface is frozen in the 25 [Myc API baseline](contracts/api_baselines/myc.txt). 26 27 Status publication and cached snapshots can be obtained only through the 28 validated factory and its sealed handles: 29 30 ```compile_fail 31 use myc::{MycStatusPublisher, MycStatusSnapshot}; 32 33 let _publisher = MycStatusPublisher {}; 34 let _snapshot = MycStatusSnapshot {}; 35 ``` 36 37 The native package, artifact, and dependency-trust boundary is frozen by 38 `contracts/services_hardening/native_release.v3.json`. Linux x86_64 and 39 aarch64 are the only admitted native artifact targets. `cargo xtask 40 native-release` consumes an exact prebuilt target binary from a clean Git head 41 and deterministically writes or checks the complete binary/source archive, 42 systemd, configuration, source-lock, SBOM, notices, checksum, manifest, and 43 unsigned provenance inventory outside the source tree. The source archive 44 vendors the exact locked Cargo graph and proves an offline metadata read before 45 packaging. Signing credentials and parent-owned human documentation are never 46 inputs. 47 48 The standalone Linux systemd boundary is frozen by 49 `contracts/services_hardening/systemd_qualification.v1.json` and checked by 50 `scripts/verify-systemd.sh`. The instance unit uses the canonical service-host 51 paths, fixed unprivileged account, restrictive directory modes and umask, 52 fixed restart delay, bounded stop behavior, empty capabilities, no environment-based secret 53 input, and the reviewed filesystem, kernel, namespace, process, and address- 54 family protections. The Linux-only verifier requires systemd 252 or newer, 55 runs syntax verification, and rejects an offline security exposure above 3.0. 56 Type `simple` remains deliberate: readiness is the cached CLI/admin contract, 57 not `sd_notify`. Compatibility-sensitive `MemoryDenyWriteExecute` and syscall 58 filters remain deferred to the Step 229 integration wave rather than being 59 enabled without real-binary evidence. This qualification does not install, 60 enable, start, stop, or deploy a production service. 61 62 The canonical service source lock binds the exact active public Lib cohort, 63 Cargo lock, verified Lib source archive, toolchain, feature profile, and 64 service contract versions. Source-lock v3 binds the public flake lock to the 65 same exact Lib revision as Cargo and records qualified Nix material for only 66 macOS aarch64 and Linux x86_64. The Linux-only NixOS module and unsigned OCI 67 derivation are build outputs; signing, tags, publication, deployment, and 68 production activation remain unclaimed. 69 70 ## Hardened v1 configuration contract 71 72 The target service configuration is frozen by 73 `contracts/services_hardening/config.v1.schema.json` and the canonical 74 non-secret `config.v1.example.toml`. It is one strict, immutable TOML document 75 with explicit identity, relay, authorization, rate, and discovery authority. 76 Only reviewed bounded operational leaves have defaults. Bootstrap profile, 77 instance, repo-local root, and config-path selection are CLI concerns and are 78 not document fields. 79 80 The hardened CLI parser admits the common command tree in one parse. It 81 requires explicit `--profile <service-host|interactive|repo-local>` and 82 `--instance <validated-instance-id>` selectors, requires an absolute 83 `--repo-local-root` only for `repo-local`, and accepts only an optional absolute 84 `--config` path. Its exact command inventory is `run`; `config 85 init|validate|show|schema|apply`; `state init|status|backup|restore|verify|migrate`; 86 `identity init|status|export-public`; `status`; and `doctor`. Identity rotation 87 is an offline create-new/config-apply lifecycle and is intentionally absent 88 from the live CLI and Unix-admin inventories. 89 The process binary uses only this parser and consumes its sealed execution plan 90 exactly once. Every command reaches its governed config, state, identity, 91 Unix-admin, doctor, or daemon authority. `run` installs the authoritative 92 bounded daemon graph; no admitted command can return success through a 93 prototype or unavailable-operation fallback. 94 95 The selected absolute config path is opened no-follow through its retained 96 parent descriptor. The loader requires a regular, single-link, 97 effective-user-owned file with no group/other-write permission, caps bytes 98 before parsing, and revalidates device, inode, length, and parent identity after 99 the read. Config initialization consumes bounded non-secret TOML from stdin and 100 uses create-new `0600` persistence plus file and parent synchronization. Secret 101 identity provisioning is a separate fixed 117-byte zeroizing stdin document; 102 secret arguments, environment values, JSON strings, and trailing bytes are not 103 accepted. 104 105 One binary-owned Tokio runtime is created from the validated fixed thread 106 limits for each asynchronous command process; there is no CPU-derived default 107 or library-owned runtime. Existing-state commands discover actual metadata 108 through the retained shared intent. Offline backup writes the exact canonical 109 manifest bytes to stdout without a trailing newline, so direct redirection 110 preserves the bytes bound by its digest. Restore derives expected backup identity 111 from the trusted manifest digest rather than requiring the damaged live 112 database to open, and exclusive commands retain the writer-authority boundary. 113 Deployment directory provisioning remains outside the service executable. 114 115 The parsed invocation is projected once into a sealed execution plan. `run` 116 selects daemon authority; config, exclusive state/identity provisioning, and 117 doctor select offline authority; state/identity/service inspection and live 118 mutations select the permissioned Unix-admin authority. Only explicitly 119 read-only status, backup, and public-identity operations may fall back when a 120 later executor proves the daemon writer lock is free. No live plan carries 121 SQLite authority. 122 123 The active doctor boundary executes the exact 13-check operator inventory in 124 contract order under fixed per-check deadlines. Check implementations retain 125 their filesystem, SQLite, provider, bind, network, relay, and clock authority; 126 only closed pass/fail/skipped observations cross into the report builder. The 127 builder enforces required-check semantics, returns exit 6 for required failure 128 or timeout, and emits at most 8,192 bytes of compact canonical JSON using only 129 fixed summaries and remediation codes. Raw errors, paths, relay URLs, 130 credentials, public keys, and arbitrary detail strings cannot enter the report. 131 A pass requires every machine-listed scope facet. Probe futures own their work, 132 must stop safely when dropped at deadline, and may not detach later mutation. 133 The production adapter composes secure path and disk inspection, writer-lock 134 and SQLite authorities, exact schema and outbox checks, provider opening and 135 Describe verification, validated bind/network policy, and bounded required- 136 relay reads. It never publishes a relay event. Clock skew remains the sole 137 optional `Skipped` check until a trusted time source is governed. 138 139 The service status boundary uses the shared service-host lifecycle contract 140 behind one Myc-owned non-clone publisher and cloneable passive readers. Each 141 publication validates the lifecycle transition and encodes the complete 142 bounded `service_status_v1` payload before atomically replacing the single 143 retained immutable snapshot. Repeated reads return that exact cached value and 144 perform no SQLite, provider, relay, credential, DNS, clock, filesystem, or 145 fresh-probe work. Connection counts use the closed pending/active/denied/ 146 expired vocabulary, identity health uses the fixed transport/user/discovery 147 roles, failed publication preserves the last valid snapshot, and detailed 148 status remains local to the permissioned Unix-admin surface. Status reason 149 codes use a closed twelve-value vocabulary; arbitrary strings cannot enter the 150 cached response. 151 152 The optional TCP operations adapter consumes that same supervisor publication 153 through a second passive bounded projection and delegates the transport to the 154 source-locked service-host server. It exposes exactly HTTP/1.1 `GET /livez`, 155 `GET /readyz`, and `GET /metrics`; every other method, path, or query is 156 unrouteable. The two Prometheus families are the cached phase and cached 157 readiness bit with only the closed phase label. Requests perform no SQLite, 158 filesystem, provider, relay, credential, DNS, or fresh-probe work; the shared 159 transport still reads its monotonic deadline clock. 160 Detailed status, configuration, paths, identities, connection/audit data, and 161 all mutations remain on the permissioned Unix-admin surface. The listener is 162 disabled unless the validated configuration explicitly enables and binds it, 163 and its parser floor, headers, response, concurrency, deadline, and idle bounds 164 remain enforced by the shared server. 165 166 Process outcomes use one exact seven-value vocabulary with exit codes 0 167 through 6. Diagnostics are compact single-line JSON on stderr; result data is 168 reserved for stdout, and Myc never writes log files. The structured record 169 admits only the closed level, event, result, lifecycle, task-failure, and signal 170 codes. It accepts no caller text, path, SQL, raw cause, identity, relay URL, 171 credential, secret, or decrypted content. Every public Myc error remains a 172 crate-owned source-free classification, so ordinary `Display`, `Debug`, and 173 whole-chain traversal cannot bypass redaction. Current binary dispatch reports 174 invalid input as exit 2 and service dependency unavailability as exit 3. The 175 Myc runtime owns one sealed, bounded critical-task graph over the shared supervisor: 176 task error, panic, join failure, unexpected cancellation, or critical success 177 before cancellation coordinates shutdown, joins every task, and maps to the 178 fixed nonzero process result. Tasks receive only a cooperative cancellation 179 observer; task names and handles remain internal. The binary owns signal 180 installation. The graph uses one configured absolute graceful-shutdown deadline 181 for mutation rejection, ingress and operations drain, 182 recoverable-work persistence, network and SQLite close, and socket close; it 183 adds no hidden second cleanup budget. 184 185 `parse_myc_config_v1` caps original bytes before decoding, checks the schema 186 header before closed contract admission, rejects duplicate, null, unknown, and 187 semantically inconsistent input, and returns an immutable document plus a 188 deterministic redacted effective-configuration projection. Every projected 189 leaf records whether it came from the document or one of the exact governed 190 default authorities. Ordinary errors and `Debug` output contain no source 191 text, paths, credentials, relay URLs, or identity values. 192 193 The prototype environment loader, `.env` example, environment selectors, 194 implicit command/profile selection, compatibility aliases, and arbitrary leaf 195 flags have been removed. Bootstrap now resolves a sealed runtime context from 196 the validated CLI profile and typed instance ID through the source-locked 197 `radroots_runtime_paths` authority. Config, state, cache, logs, run, secrets, 198 `config.toml`, `state.sqlite`, `state.lock`, and `admin.sock` are derived under 199 the exact `services/myc/<instance>` namespace. The service contains no local 200 host-environment resolver, worker namespace, ambient selector, or implicit 201 path default. An explicit absolute `--config` may select the document to read 202 without changing the canonical common artifact inventory. 203 204 ## Governed state boundary 205 206 Create-new initialization reserves the shared schema-v1 metadata and migration 207 ledger, retains exclusive writer authority, applies the exact Myc schema-v2 208 through schema-v12 migrations, binds the normalized configuration, expected 209 identity roles, and policy versions through a sealed typed repository, and 210 explicitly closes the host before reporting success. Existing writable open can 211 resume any exact v1 through v11 prefix or admit the current v12 catalog; 212 read-only inspection requires the current catalog and exact latest Myc binding. 213 214 Schema v10 adds an append-only configuration-binding history capped at exactly 215 1,024 generations. Generation 1 is seeded only after the v10 migration commits, 216 including for an upgraded v9 database, while the immutable original birth 217 record remains unchanged. `apply_configuration` is admitted only through an 218 exclusive writable host and independently validates the retained current and 219 candidate documents before one atomic append. A changed identity expires live 220 sessions and pending challenges; permission narrowing expires only sessions 221 whose retained grants are removed. Removing or changing a relay that is still 222 referenced by nonterminal delivery work fails closed, while safe relay additions 223 remain admissible. Exact replay returns the retained generation without another 224 append or revocation, including after an ambiguous caller result. Future startup 225 must present the latest normalized config and public-identity binding. The 226 history stores only digests, public identities, 227 closed contract versions, injected application evidence, and safe build 228 identity; it stores no credentials, provider envelopes, paths, or relay URLs. 229 230 Schema v11 adds the bounded admin-operation journal. It binds each mutation's 231 validated operation ID to its fixed route and canonical request digest, retains 232 at most 128 unresolved Prepared records and 4,096 completed responses, caps a 233 replayed response model at 8,192 bytes, and prunes only a bounded expired 234 completed prefix before admission. The journal stores no request body, path, 235 correlation ID, credential, bundle path, or secret. Completed responses use an 236 explicit retention policy whose admitted range is 1 through 31,536,000,000 237 milliseconds; the governed operating value is seven days. 238 The admin response transport admits at least 8,382 UTF-8 bytes so the maximum 239 retained model plus the maximum safe correlation identity always fits its 240 canonical success envelope. 241 242 Schema v12 adds immutable response authority for a connect request awaiting 243 explicit approval. Myc signs and atomically retains the exact 244 `pending_connection` response with its initial delivery job before relay 245 publication, without recording a false terminal operation completion. Exact 246 replay and delivery use only the retained signed bytes, and a later terminal 247 response cannot conflict with the pending authority. 248 249 The Step 159 provider and delivery boundary is sealed inside the crate. Both 250 governed provider kinds execute only fully bound operations, and every result 251 is independently verified before it becomes authority. Protected blocking 252 work is joined, local-signer calls use the hardened Unix-admin client, and no 253 raw provider client, secret, callback, or dependency-owned error crosses the 254 public API. 255 256 Relay publication uses only the exact source-locked 257 `radroots_transport_nostr` adapter. Preparation validates the exact committed, 258 signature-verified event bytes without network I/O. The delivery worker then 259 persists Submitted immediately before execution. Accepted, rejected, 260 transport-failed, and unknown acknowledgements remain distinct; cancellation 261 or lost acknowledgement after Submitted is durably unknown, and retries never 262 alter the committed bytes. Provider or relay work never occurs inside a SQLite 263 transaction. The secure command executor and production daemon graph use these 264 same provider, relay, and exact-byte delivery boundaries. 265 266 The production `run` path owns the exact five-role bounded graph: 267 `admin_server`, optional `operations_server`, `relay_ingress`, 268 `provider_dispatch`, and `delivery_outbox`. It creates no task per request or 269 relay. Required relay subscriptions and provider handshakes complete before 270 Ready; bounded reconnect publishes Unready when a required dependency is lost, 271 while optional operations loss publishes Degraded. NIP-46 dispatch verifies, 272 decrypts, admits, authorizes, executes providers outside transactions, 273 re-encrypts in the verified request context, signs through the transport provider, 274 and atomically commits completion, exact response bytes, immutable targets, 275 and initial outbox state. Completed replay never re-executes a provider. 276 277 Schema v8 adds immutable NIP-46 operation-completion evidence. The Step 147 278 integration checkpoint binds each durable request to its stable operation and 279 correlation identities, terminal connect authority or exact active session, 280 safe completion reason, and any independently verified inner signed-event 281 bytes and digest. Logout revocation and completion insertion share one 282 transaction, exact replay returns the stored decision, and failed transactions 283 expose neither effect. Protected provider output is never persisted. This is an 284 integration component, not the final production response boundary: Step 148 285 must compose it with the outer signed response bytes, immutable relay targets, 286 and initial outbox state in one transaction before RCLD-RSHR-080 can be 287 promoted to `master`. 288 289 Schema v9 closes that production boundary. `commit_nip46_response` admits only 290 an independently signature-verified, canonical kind-24133 response bound to the 291 original client and exact provider signing operation. One SQLite transaction 292 commits the Step 147 completion, exact response bytes and SHA-256 identity, 293 immutable configured relay targets, pending delivery job, and zero-attempt 294 target state. Exact replay returns only the retained response bytes; partial 295 legacy completion state and mismatched replay fail closed. Provider execution 296 and relay I/O remain outside the transaction. 297 298 Step 149 closes the repository-owned delivery recovery boundary without 299 claiming the final daemon task graph. New jobs can be created only by the 300 atomic signed-response or discovery commit and are rejected at the configured 301 active-outbox ceiling. Attempt resolution persists caller-injected, 302 attempt-cap-bounded full jitter; restart recovery scans fixed 128-job cursor 303 batches, revalidates exact signed source bytes and bounded attempt histories, 304 recovers only expired leases, and idempotently promotes proven desired 305 discovery. It performs no relay I/O and creates no task, clock, or entropy 306 authority. Explicit desired/current offline NIP-05 export re-reads verified 307 state, works through read-only inspection, and returns canonical compact 308 `names` plus NIP-46 discovery JSON without hosting it. 309 310 The implemented v1 Myc administration adapter registers the exact 19-route 311 inventory and validates every request and response against all 32 model 312 references in `contracts/services_hardening/operator_contract.v1.json`. It 313 reuses the hardened Lib HTTP/1.1-over-Unix server for original-wire duplicate 314 and null rejection, percent-decoded bounded path parameters, peer admission, 315 deadlines, concurrency, body limits, and effective correlation IDs. The Myc 316 boundary additionally rejects unknown or missing model fields, invalid query 317 types, noncanonical response JSON, unsafe URLs and identifiers, and response 318 model drift. Raw shared-host routers and JSON values never cross the public 319 API. 320 321 The domain handler receives compact canonical model bytes plus the durable 322 operation ID. A successful mutation means its contract-defined local effect 323 and operation audit are committed; it does not claim relay submission or 324 delivery. Identical operation-ID reuse must return the original committed 325 result, different-byte reuse returns `operation_id_conflict`, and pagination 326 cursors remain authenticated to the same route, filters, and snapshot. Unit 13 327 seals that handler boundary inside the production `MycAdminServer`, 328 projects the exact admitted admin transport limits, and binds only the 329 canonical permissioned `admin.sock` through the shared host authority. The raw 330 router, listener, entropy source, and cancellation token remain private. The 331 existing sole status publisher feeds both detailed local status and the 332 optional passive three-route TCP operations server, while doctor continues to 333 accept only its exact injected 13-check probe inventory. Unit 14 supplies the 334 secure CLI/config bootstrap and concrete doctor probes. Unit 15 alone owns task 335 spawning, provider/relay wiring, readiness, reconnect, and phase-aware 336 shutdown. 337 338 The transport capability and admitted request remain non-forgeable outside 339 the crate: 340 341 ```compile_fail 342 use myc::{MycAdminRequestDocument, MycAdminRouter}; 343 344 let _request = MycAdminRequestDocument {}; 345 let _router = MycAdminRouter {}; 346 ``` 347 348 The public Myc repository exposes no raw pool, connection, transaction-control 349 handle, path, or SQL. Binding and request-admission mutations execute only 350 inside the shared `ServiceSqliteTransaction` runner. Provider and relay work 351 cannot occur inside that transaction boundary. The v2 binding table, v3 352 request/dedup tables, and v4 connection, permission, request-decision, and 353 authorization-challenge tables and guards are checksum-pinned service-owned 354 schema objects. Schema v5 adds checksum-pinned audit-sequence, safe operation 355 audit, request-audit binding, and bounded rate-window objects. Schema v6 adds 356 checksum-pinned publication-job, target, attempt, transition-guard, and 357 no-delete objects. Schema v7 adds desired/current discovery state, exact signed 358 NIP-89 event bytes, deterministic NIP-05 projection inputs, and their delivery 359 binding. 360 361 The earlier JSON signer store, JSONL audit log, separate signer/audit/outbox 362 SQLite databases, prototype import/backup adapter, independent migration 363 directories, and their runtime/operability consumers have been removed. The 364 only authoritative service-state database is the canonical `state.sqlite` and 365 the only writer authority is its retained `state.lock`; there is no backend 366 selection, compatibility reader, prototype importer, or secondary migration 367 engine. 368 369 The side-effect-free signer-provider contract admits exactly `encrypted_file` 370 and `local_signer` assignments for the explicit transport, user, and optional 371 discovery roles. It freezes the seven-operation capability vocabulary, exact 372 role requirements, stable provider-instance/operation/correlation identities, 373 absolute deadlines, bounded semantic input and untrusted output, local-signer 374 resource limits, and logical credential references. Construction derives from 375 the already admitted v1 configuration, exposes no provider path or secret in 376 ordinary Debug, and performs no filesystem, credential, socket, clock, task, 377 or cryptographic work. Envelope execution, credential resolution, Unix-socket 378 transport, and independent result verification remain later checkpoints. 379 380 The encrypted-file provider now uses the source-locked `radroots_secrets` v2 381 context-bound envelope behind a sealed Myc boundary. Offline provisioning 382 requires explicit identity, data-key, envelope-nonce, and wrapping-nonce 383 material; verifies the derived public key before persistence; and creates one 384 owner-only envelope without overwrite. Existing reads are bounded, no-follow, 385 single-link, owner-only, context/reference checked, and independently verify 386 the decrypted public key against the configured role identity. Protected 387 material is zeroizing and absent from diagnostics. The service-state backup 388 inventory remains exactly `state.sqlite`: encrypted identity envelopes, 389 wrapping credentials, and plaintext identity material are excluded. Canonical 390 credential artifact resolution remains Step 133 and ordinary run never 391 provisions an identity. 392 393 Wrapping credentials now resolve only from the shared validated 394 `ServiceCredentialArtifactName` beneath the sealed runtime context's canonical 395 instance secrets root. The resolver accepts no path or credential bytes and 396 reads only an existing exact 32-byte, euid-owned, single-link artifact through 397 descriptor-relative no-follow admission. Service-host deployments inject or 398 mount that fixed file; repo-local developers provision it offline. Interactive 399 resolution is unsupported, and TOML, environment, process arguments, adjacent 400 envelope files, ordinary run, and state backup neither carry nor create the 401 credential. 402 403 Local-signer calls use the source-locked hardened Lib administration client for 404 strict HTTP/1.1 JSON over the configured Unix socket. One fixed 405 `/v1/provider/operation` endpoint carries a closed internally tagged operation 406 and result plus exact provider instance, role, operation/correlation IDs, 407 absolute deadline, expected identity, capability, and contract version. The 408 validated binding supplies body, deadline, and per-client concurrency limits. 409 Transport success remains sealed and semantically untrusted until independent 410 Step 135 verification; cancellation does not prove the signer had no effect, 411 and signing is never publication. No TCP, browser origin, or child process is 412 part of this boundary. 413 414 Independent provider verification uses injected completion time and rejects a 415 late result before semantic exposure. It rebinds the configured role, 416 instance, identity, operation/correlation IDs, deadline, capability, NIP peer, 417 direction, and version. Describe/public-identity results must match the 418 configured identity and limits; signed Nostr events must preserve the exact 419 canonical unsigned fields, pass event-ID and Schnorr verification, and retain 420 the exact verified canonical response bytes; NIP-04 and NIP-44 ciphertext must 421 have canonical protocol shape and exact padding length where the plaintext is 422 known. NIP-44 v2 plaintext is admitted only through its exact 65,408-byte 423 implementation ceiling. Verified output remains sealed and redacted, and 424 neither verification nor signing constitutes publication. 425 426 The obsolete prototype provider tree has been removed. Myc ships no account 427 keyring, managed-account selector, plaintext or adjacent-key file adapter, 428 child-process signer, implicit host identity, generic remote-session signer, 429 or legacy logging/client wrapper. Its removed production dependencies and 430 Tokio process capability are absent from the locked graph; the active typed 431 provider contract, encrypted envelope, credential resolver, local-signer 432 transport, and independent verifier are the only provider boundaries. 433 434 The existing-only runtime foundation owns the writable state host, retained 435 provider capabilities, and a shared Lib task supervisor. Encrypted-file 436 identities open only in synchronously joined one-shot startup tasks; 437 local-signer clients perform no construction-time I/O and remain unready until 438 their later governed handshake. A passive closed prerequisite snapshot keeps 439 state, providers, recovery, required relays, admin, and optional operations 440 conditions explicit without claiming the later status cache or final daemon 441 task graph. 442 443 Signer-request admission validates bounded client, request, event, method, 444 canonical request, injected operation entropy, and injected time evidence 445 before storage. Stable domain-separated operation and correlation identities 446 bind the logical client request to its persisted entropy evidence. Event 447 identity and logical request identity retain distinct durable deduplication 448 records, so an exact replay is idempotent while event or request reuse with 449 different normalized content records a conflict without retaining the 450 decrypted request bytes. Replay and conflict counters are bounded and 451 survive explicit close and reopen; retention remains owned by its later state 452 checkpoint. 453 454 Connection admission consumes an already-admitted `connect` operation and an 455 explicit policy generation. Trusted admission creates an active connection; 456 explicit approval creates a pending connection that can transition once to an 457 operator-approved or operator-denied terminal decision; direct policy denial 458 records a durable decision without creating a connection or approval workflow. 459 Requested and granted permissions are closed, bounded, and independently 460 bound. Authorization challenges are issued only for a non-connect operation 461 bound to an active connection, use an operator-owned canonical URL plus 462 injected entropy and time, and transition once to authorized or expired. 463 Exact retries return the original durable identity or terminal state, including 464 after explicit close and reopen. 465 466 Connection admission uses one bounded global window plus one configured relay 467 window, so arbitrary client keys cannot create persistent subjects before a 468 connection exists. Challenge creation and authorization use distinct stable 469 connection-scoped windows. Exact saturation creates no connection, decision, 470 challenge, or authorization transition beyond the accepted bound, and a 471 retained rate rejection is replay-stable. Safe audit records preserve exact 472 typed operation/correlation bindings and use closed category, outcome, and 473 reason vocabularies; snapshot pagination is bounded and Debug output redacts 474 identity. Explicit bounded compaction is correlation-idempotent and retires 475 only expired rate-window and old safe-audit evidence. It never removes schema 476 history, metadata, connections, decisions, permissions, or challenges. 477 478 Delivery admission copies the exact normalized write-relay inventory, 479 required-target flags, acknowledgement policy, retry ceiling, backoff, and 480 attempt deadline into one immutable publication job. Target leases and attempt 481 records are advanced only through the shared transaction runner; relay I/O is 482 never awaited while a transaction is open. Exact retries are idempotent, stale 483 leases recover through injected time evidence, and an acknowledgement whose 484 outcome is not known remains `unknown` rather than being relabeled as failure 485 or delivery. This checkpoint binds an artifact digest and precommit identity; 486 the exact committed signed-event bytes and discovery projection are owned by 487 their subsequent state checkpoints. 488 489 Discovery desired state is committed atomically with signature-verified, 490 canonical NIP-89 event bytes, deterministic NIP-05 projection inputs, the 491 immutable relay targets, and the initial delivery job. The desired generation 492 may advance independently, while current generation advances only after the 493 corresponding desired job has proven the configured delivery policy. Restart 494 reads return the same committed event bytes and projection inputs; publication 495 and hosted NIP-05 responses remain later runtime concerns and never run inside 496 the SQLite transaction. 497 498 Explicit state initialization validates runtime identity, build evidence, and 499 the complete migration/schema catalogs before invoking the runtime-path 500 directory plan. That plan alone may provision the exact interactive 501 `services/myc/<instance>` suffix; service-host deployment roots and suffixes 502 must already exist. The shared service-SQLite initializer owns the one 503 transaction and exposes only its sealed typed SQLx executor. Existing writable 504 and inspection opens never provision directories or create missing state. 505 506 Writable hosts expose Myc-bound online-backup and active-integrity operations. 507 Backup verification retains the exact admitted member inode, and 508 offline staging derives the same runtime paths, database identity, migration 509 catalog, and schema catalog from sealed Myc evidence. Finalization returns no 510 open host; the next writable open alone reconciles durable recovery evidence. 511 Read-only hosts cannot capture backups, and any live host prevents offline 512 restore authority. Cancellation, explicit close, and cleanup behavior remain 513 owned by the source-locked shared SQLx host; Myc maps every public failure to a 514 stable source-free classification. 515 516 ## Executable qualification 517 518 The Step 161 process qualification is frozen by 519 `contracts/services_hardening/process_qualification.v1.json`. It runs the 520 actual `myc` executable under fixed deadlines, bounded captured output, eight 521 concurrent inspection processes, 32 deterministic reopen iterations, and one 522 64 MiB crash fixture. External process termination exercises interrupted 523 backup and pre-marker restore boundaries without adding a production 524 failpoint, hidden command, environment selector, feature, or detached test 525 worker. An interrupted backup preserves the live database and leaves explicit 526 collision evidence. An orphan restore stage prevents admission until an 527 operator removes the owned test fixture, while a durable replacement marker is 528 reconciled only by the next governed writable process open. 529 530 The executable corpus composes with the exact Myc component-level atomicity, 531 backlog, saturation, recovery, property, and adversarial tests and the 532 source-locked shared SQLx initialization, transaction, backup, close, marker, 533 restore, and `SIGKILL` failpoint corpus named by that contract. Qualification 534 adds no runtime authority and makes no RCLD promotion, parent-alignment, Nix, 535 OCI, signing, publication, or deployment claim. 536 537 ## NIP-46 runtime contract 538 539 Myc listens for encrypted kind-24133 requests on the exact configured relay 540 inventory. The signer transport identity authors and encrypts 541 protocol responses; the separate user identity is returned by 542 `get_public_key` and signs user events. Client-supplied connect metadata is a 543 bounded, display-only hint and never changes approval, authentication, or 544 permissions. 545 546 The public approval default is `explicit_user`. Trusted and denied clients, 547 permission ceilings, allowed signing kinds, auth challenges, relay switching, 548 and delivery policy are represented only by the strict v1 TOML contract. A 549 successful `logout` publishes its acknowledgement before 550 revoking the session. Failed acknowledgement delivery remains recoverable on 551 restart, while requests from a revoked session remain unauthorized until a new 552 connect is approved. 553 554 Myc rejects invalid signatures, wrong recipient tags, empty request IDs, 555 malformed ciphertext, and duplicate event delivery before dispatch. Runtime 556 state and audit output do not log client private keys or raw connection URIs. 557 Signer-authored protocol responses use the checked generic-event boundary from 558 `radroots_nostr`. External custody commands receive canonical unsigned-event 559 JSON only after typed-authoring policy succeeds, and Myc accepts their result 560 only when the author and event id match the exact request and the complete 561 NIP-01 event verifies. Caller-supplied NIP-46 `sign_event` payloads remain a 562 separate low-level interoperability boundary and receive the same exact-result 563 integrity checks without acquiring a typed product-authoring claim. 564 The production external-command executor drains stdout and stderr concurrently, 565 enforces bounded output, applies one end-to-end timeout, kills and reaps timed 566 out helpers, and releases Myc's multi-thread Tokio worker while waiting. 567 Helper-provided stderr and protocol error text are never copied into operator 568 errors. 569 570 The default Cargo feature profile is `service-host`. Validate the standalone 571 crate through extbuild: 572 573 ```text 574 cargo extbuild doctor 575 cargo extbuild run -- ./scripts/verify-boundaries.sh 576 cargo extbuild run -- ./scripts/verify-supply-chain.sh 577 cargo extbuild run -- ./scripts/release-acceptance.sh 578 ``` 579 580 After building one of the two admitted Linux targets, create and then 581 byte-check an external release directory with explicit deterministic evidence: 582 583 ```text 584 cargo extbuild run -- cargo xtask native-release --mode write --target <aarch64-unknown-linux-gnu|x86_64-unknown-linux-gnu> --binary <absolute-binary> --output <absolute-new-directory> --source-date-epoch <positive-u32-seconds> 585 cargo extbuild run -- cargo xtask native-release --mode check --target <same-target> --binary <same-absolute-binary> --output <same-absolute-directory> --source-date-epoch <same-seconds> 586 ``` 587 588 The flake exposes the Myc package, application, checks, and development shell 589 for `aarch64-darwin` and `x86_64-linux`, plus the NixOS module and unsigned OCI 590 derivation for `x86_64-linux`. Run Nix and narrower ad hoc Cargo commands 591 through `cargo extbuild run --` from this repository root. 592 593 ## Copyright 594 595 Except as otherwise noted, all files in the `myc` distribution are 596 597 `Copyright (c) 2026 Tyson Lupul` 598 599 ## License 600 601 This repository is licensed under AGPL-3.0-or-later. See LICENSE.