lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

CHANGELOG.md (26557B)


      1 # Changelog
      2 
      3 All notable changes to the Radroots core libraries are documented in this file.
      4 
      5 ## [1.0.0-alpha.1]
      6 
      7 This alpha is not published until the repository release preflight and external
      8 publish policy both pass for the same source revision.
      9 
     10 ### Changed
     11 
     12 - Event-store schema initialization now uses a transactional, checksummed
     13   migration authority with exact legacy-baseline adoption, shared-database
     14   catalog scoping, tamper-evident fail-closed managed history, exact catalog
     15   deltas, SQLite and FTS5 integrity validation, a no-write current-schema fast
     16   path, and read-only schema status inspection. Rollback is a terminal,
     17   pool-closing maintenance operation with a public version floor. Raw migration
     18   SQL and unrestricted destructive rollback are no longer public APIs.
     19 - Event-store schema version `2` now installs a byte-pinned NIP-09
     20   reconciliation hook over immutable NIP-01, addressable-feed-v1, and
     21   registry-v7 semantics. The hook re-verifies durable raw authority and
     22   persists generation-partitioned event coordinates, deletion requests,
     23   normalized targets, canonical addressable state, and append-only
     24   transitions without rewriting or deleting raw events. Projection cursors
     25   now bind to the active source generation; version or generation changes use
     26   a typed, revision-bound rebuild ticket that rejects stale, replayed, raced,
     27   and ABA-replaced resets. Initial reconciliation and repeated rebuilds use a
     28   marker-first transaction whose deferred commit barrier rejects partial
     29   authority; every successful rebuild appends a fresh generation while
     30   preserving immutable generation and transition history. Critical owned,
     31   borrowed-savepoint, and extension wrapper bodies now bind production AST
     32   identity, as do the isolated reconciliation-core and raw-head storage
     33   modules. Post-core orchestration receives a private transaction capability
     34   instead of SQLx authority; its fixed literal-SQL methods confine
     35   trade/observation writes to declared operation/table pairs. A lightweight
     36   source/transition/schema seal runs after that capability is dropped and
     37   rejects protocol-authority drift without introducing per-ingest full-table
     38   scans. Schema, pool, status, and ingest boundaries bind governed access to
     39   SQLite `main`, reject ASCII-case-insensitive temporary-schema collisions,
     40   preserve unrelated shared-schema foreign-key evidence, and retain both the
     41   primary ingest and rollback errors when rollback also fails.
     42 - Transport targets and Reticulum destinations now keep identity-bearing
     43   fields private, expose read-only accessors, and revalidate canonical URI,
     44   scope, label, routing, and fingerprint invariants during deserialization.
     45   Nostr relay targets now use strict ASCII host, port, path, default-port, and
     46   IPv6 canonicalization shared with the relay adapter. Policy-free relay URL
     47   and target-set serialization has been removed; duplicate target sets fail,
     48   and fetch requests require a typed nonempty target set. Adapter fetch items
     49   are canonicalized and must belong to that request before any store mutation,
     50   while the request timestamp is the sole observation-time authority. Public
     51   relay policy is explicitly for trusted configured `wss` hostnames and
     52   rejects local, special-use, single-label, and forbidden literal
     53   destinations; localhost policy accepts exact loopback hosts only. The
     54   default SDK connector does not make attacker-controlled DNS names an SSRF
     55   boundary. Event-store diagnostic messages must be caller-redacted,
     56   canonical, control-free, nonempty, and no larger than 4 KiB; automatic relay
     57   publish observations no longer persist remote outcome text. Observation v1
     58   remains endpoint-level and intentionally does not represent scoped
     59   Reticulum or local-target identity; scoped evidence stays in transport
     60   delivery receipts. This
     61   intentionally changes fingerprints and public APIs for spellings and
     62   configurations previously accepted. Because this is an unreleased alpha
     63   contract, databases and serialized configuration containing those legacy
     64   identities are not migrated: development instances must be reset and
     65   canonically reseeded rather than silently reinterpreted.
     66 - Geocoder locality and reverse results now expose administrative subdivision
     67   identifiers as opaque strings. SQLite integer and text values normalize to
     68   the same lossless public representation, and mixed-storage candidate order
     69   remains deterministic.
     70 - Default GeoNames asset installation now uses cancellable asynchronous DNS,
     71   explicit connect, response, read, and total deadlines, denied redirects, and
     72   bounded runtime shutdown. HTTP bodies stream through incremental length and
     73   SHA-256 verification into a same-directory tempfile that is synced, checked
     74   for SQLite integrity and schema, and atomically persisted. Public download
     75   errors expose stable typed phases and detail fields instead of
     76   `reqwest::Error`; trusted injected fetchers retain a bounded byte adapter.
     77 - Trusted event-contract admission now has one signature-verified entry point.
     78   Profile, root Post, Reply, Comment, DeletionRequest, and FoodAvailability
     79   retain typed admitted values; other registered events require full contract
     80   shape validation, while unsupported matching and invalid shapes remain
     81   distinct failures.
     82 - Event-store ingest now verifies before durable admission, retains every
     83   verified durable candidate for registry-independent raw-head reduction, and
     84   separates immutable valid-stream replay from current visibility. Explicit
     85   raw, valid, raw-head, visibility, and visible-head APIs replace ambiguous
     86   projection/head reads; projection cursors require an expected version and a
     87   monotonic prior-sequence compare-and-swap. Verified ephemeral events receive
     88   an explicit not-persisted outcome and allocate no raw sequence, tags,
     89   observations, or heads. Read-only consumers can inspect the same fail-closed
     90   status summary from an initialized pool without duplicating schema-sensitive
     91   SQL or running migrations.
     92 - Nostr fetch-ingest receipts now report exhaustive verification, contract
     93   admission, valid-stream, and current-visibility outcomes independently.
     94   Verification failures no longer share an `invalid` bucket with contract
     95   failures, unsupported admissions retain their stable code without masking
     96   visibility, and persisted events obtain visibility from the event store's
     97   central authority. Fetches enforce a 64,000 raw-event ceiling, a 64 MiB
     98   aggregate raw-JSON prefix budget, and the 256 KiB per-event wire limit before
     99   Radroots parses adapter raw JSON; after upstream SDK frame decoding, the
    100   official SDK stream applies the same retained-prefix bounds before retaining
    101   serialized adapter output. Local event-store failures abort fetch ingest as
    102   operational errors instead of being reported as malformed relay input.
    103 - Generic outbox APIs now reject every NIP-16 ephemeral event before durable
    104   queue persistence. Live-only events, including NIP-42 relay-auth and NIP-98
    105   HTTP-auth signatures, remain owned by their transport exchanges. Externally
    106   supplied SQLite pools now validate their backing mode and configure every
    107   connection before migration or writes.
    108 - Retired trade order-workflow and product-projection source files that were no
    109   longer compiled or exported have been removed. Current FoodAvailability
    110   projection ownership remains with the event store.
    111 - Event-store schema v3 adds one central current-visibility authority, a
    112   generation-bound addressable transition feed, and an atomic focused
    113   FoodAvailability projection with bounded FTS search. The successor contract
    114   authenticates schema `0003`, registry-v7 admission, exact kind scope `30402`,
    115   executable transition/projection vectors, and the frozen NIP-09 predecessor.
    116   Stored Blossom image digests use the public typed SHA-256 value.
    117 - Event-store schema v4 adds a persisted raw-source capacity seal for event
    118   rows, tag rows, and their governed UTF-8 text bytes. Unique durable ingest
    119   now refuses prospective capacity excess before mutation, database reopen
    120   performs a bounded full recount, and independent file pools serialize an
    121   exact final capacity slot. Every supplied main database must report UTF-8
    122   before schema or journal mutation. Retained source history stops at eight
    123   generations before requesting fresh-store replacement and resync, and
    124   production rollback cannot cross the migration that introduced that
    125   append-only history. The
    126   authenticated SourceMaintenance successor binds the immutable schema-v3
    127   predecessor, migration and runtime sources, breaking capacity-error API
    128   replacements, and an executable result vector. Schema v4 is intentionally
    129   non-additive: it replaces exactly the Food projection delete guard, Food image
    130   delete guard, and source rebuild-marker insert guard, requires that exact
    131   symmetric catalog delta, and restores the exact v3 trigger SQL on rollback.
    132   A drifted v3 predecessor is rejected atomically rather than repaired during
    133   upgrade; repair authorization is reserved for a future rebuild after exact
    134   managed-v4 catalog, ledger, and migration history plus immutable raw/source
    135   lineage and capacity validation. Derived hook state is the repair target,
    136   not a repair precondition. The former
    137   `RadrootsEventStoreReconciliationResource` type and
    138   `ReconciliationCapacityExceeded` error variant are replaced by the
    139   versioned source-capacity resource and typed capacity/history errors.
    140 - Bare-envelope replica ingestion is quarantined behind the explicit,
    141   non-default `legacy-ingest` feature. Default replica APIs expose emit and sync
    142   surfaces only; a future product ingest boundary must consume a store-produced
    143   verified, valid-stream-eligible, currently visible admission.
    144 - Blossom blob URLs now validate complete raw Unicode text before URL parsing
    145   and exact raw ASCII DNS label grammar before returning a typed value. Unicode
    146   control/format text, implicit IDNA conversion, empty labels, underscores,
    147   edge hyphens, and oversized DNS names can no longer enter approved or
    148   byte-verified media typestates; URL-parser-valid explicit ASCII punycode and
    149   canonical IP authorities remain supported.
    150 - NIP-99 kind `30402` now has an explicit two-level taxonomy: the standard
    151   protocol kind and coordinate are **Classified Listing**, while the richer
    152   Radroots farm, bin, inventory, and price profile is **Operational Listing**.
    153   Public constants, types, functions, modules, operation IDs, and generated DTO
    154   roots use those unambiguous names with no legacy `listing` aliases or modules.
    155 - Operational listing decoding now has one tag-authoritative implementation in
    156   `radroots_event_codec`. The typed parts decoder reports the established
    157   listing error taxonomy, and JSON content can no longer override canonical
    158   product, inventory, or bin tags in trade and replica consumers.
    159 - Operational listing authoring now emits canonical Markdown content from the
    160   tag-authoritative model. Tolerant inbound JSON inspection remains a decode
    161   compatibility boundary only and is not an authoring format.
    162 - Operational listing trade validation exposes one shared unsigned-model
    163   semantic reducer and a signature-verified event boundary that delegates to
    164   it after kind, marker-partition, and decoding checks. Event-store projection
    165   reconstructs and verifies the event typestate instead of trusting a plain
    166   stored envelope. Canonical authoring now invokes that reducer before draft
    167   construction and preserves its typed failure cause; the reducer rejects
    168   duplicate bin IDs and invalid quantity or price semantics in every bin.
    169 - Generic NIP-01 identifier and signature verification is now independent of
    170   knowledge decoding, and every dynamic Nostr kind conversion rejects values
    171   above `65535` instead of truncating them. Canonical-length author keys that
    172   are not valid secp256k1 curve points now return `malformed_envelope` instead
    173   of `signature_invalid`.
    174 - Calendar authoring and admission now use explicit NIP-52 authored, parsed, and
    175   admitted states for date events, time events, calendars, and RSVPs. Kind
    176   `31922` no longer emits uppercase `D`; kind `31923` derives integer UTC-day
    177   `D` values from its validated time range.
    178 - Authored profile and calendar media now share the byte-verified Blossom image
    179   proof type; unverified URLs remain inbound data and cannot enter authoring APIs.
    180 - Root kind-`1` product admission now verifies NIP-01 identity and signatures,
    181   separates every `e`-tagged event as a thread-excluded candidate without a
    182   Reply claim, and deterministically admits Ask, PhotoUpdate, or Update roots
    183   while preserving malformed media diagnostics.
    184 - NIP-10 Reply authoring now requires an opaque direct or nested type and emits
    185   exact marked `root`/`reply` event references plus required participant
    186   references. Verified inbound projection accepts preferred marked and
    187   deprecated positional threading, preserves valid supplemental references as
    188   citations, and retains malformed advisory metadata as ordered diagnostics
    189   while keeping every admitted Reply out of root-card classification.
    190 - Authored and projected NIP-10 Reply and NIP-22 Comment relay hints now share
    191   `RadrootsNostrRelayHint`, one portable, canonical visible-ASCII WebSocket URL
    192   profile instead of generic URL normalization. Strict authoring rejects
    193   noncanonical hints; tolerant verified projection preserves rejected hints
    194   verbatim in ordered raw-tag diagnostics. Relay syntax remains separate from
    195   each event profile's wire-size budgets.
    196 - Kind `1111` Comment handling now uses distinct opaque authored, verified
    197   projection, admitted-event, and sealed Nostr publication states. The strict
    198   NIP-22 profile supports only event or address roots for classified-listing
    199   kind `30402` and calendar kinds `31922` and `31923`; ordinary kind `1` and
    200   external `I`/`i` references are rejected. Legacy pseudo-thread tags carry no
    201   Comment authority, are never authored, and remain raw supplemental input.
    202 - Typed root posts now enter signing and client publication through an opaque
    203   builder with no raw tag/content mutation. Generic builder direct signing and
    204   client publication reject kind `0` plus every kind `1` before signer access;
    205   externally supplied unsigned events, NIP-46 signing, and signed-event relay
    206   remain explicit low-level Nostr interoperability with no typed product
    207   authoring claim.
    208 - Frozen drafts now carry event-contract registry version `7`, revalidate all
    209   persisted fields and the recomputed event id during deserialization and
    210   signing, and enforce explicit `GenericDraft`, `TypedOnly`, and `ReadOnly`
    211   authoring policies.
    212 - Event wire and envelope admission now reject more than 4,096 aggregate tag
    213   elements, and SDK-event conversion returns the typed envelope error instead
    214   of panicking on relay-controlled oversized input.
    215 - Strict authored posts enforce the 256 KiB compact signed-event ceiling after
    216   exact JSON escaping, in addition to per-element and aggregate decoded tag
    217   limits.
    218 - Workspace packages declare one governed version explicitly so mounted path
    219   consumers preserve it, and every internal root dependency requires that exact
    220   pre-release version.
    221 - Conformance suites now identify the `1.0.0` event-contract generation.
    222 - Release metadata records exact governed impacts for removed public types,
    223   fields, functions, modules, constants, Cargo features, and trait
    224   implementations, plus changed field types, constant values, and algorithms.
    225 
    226 ### Added
    227 
    228 - A fixed signed central-admission corpus executes every admitted variant,
    229   Update/PhotoUpdate/Ask root classification, Post-to-Reply promotion,
    230   Operational Listing fallback from Food exclusion, generic NIP-99 exclusion,
    231   unsupported kinds, malformed registered shapes, and ambiguous Food markers.
    232 - Generic protocol builders can now finalize into an opaque checked external
    233   signing request. The request preserves the standard unsigned-event JSON wire
    234   shape while preventing raw mutation or unchecked reconstruction, and it
    235   accepts only an exact author/id match with a valid NIP-01 signature.
    236 - Kind `30402` now has one allocation-free raw marker-name partition that
    237   distinguishes focused FoodAvailability, richer Operational Listing,
    238   marker-free generic NIP-99, and mixed ambiguous inputs before profile
    239   tag-shape validation.
    240 - FoodAvailability now has strict domain and authored-media input primitives
    241   for bounded identifiers and text, canonical decimal price and quantity,
    242   uppercase currency, the closed ten-unit food vocabulary, active or sold
    243   status, timestamps, dimensions, and at most 64 unique byte-verified Blossom
    244   images. Its typed codec emits exact kind-`30402` wire parts, while verified
    245   tolerant admission normalizes compatible inbound values, preserves bounded
    246   ordered image diagnostics, and excludes generic or operational listings.
    247   Strict revision comparison revalidates both signed events against authored
    248   wire semantics before enforcing a stable coordinate and `published_at` plus
    249   NIP-01 replacement ordering.
    250 - Focused FoodAvailability signing and client publication now use a sealed
    251   Nostr builder with a construction-time timestamp and no raw mutation escape.
    252   Generic signing and client publication reject focused or mixed kind-`30402`
    253   profiles before signer access; signed-event relay remains transport-only.
    254   Typed signing and publication do not attest BUD-02 upload completion.
    255 - Behind the explicit non-default `legacy-ingest` feature, legacy replica
    256   ingestion verifies kind-`30402` signatures, selects the raw addressable head
    257   before profile decoding, and sends only the Operational Listing partition to
    258   its trade-product projection. Selected focused/generic exclusions and
    259   invalid/ambiguous rejections remove an older projection while advancing the
    260   head, preventing stale projection fallback. The feature-gated public
    261   head-only helper rejects kind `30402`; callers must use profile-aware legacy
    262   ingestion so the head and projection remain atomic. These helpers are not a
    263   Phase 1 product ingest boundary.
    264 - Event-contract identification now selects Operational Listing only for its
    265   raw marker partition. Focused FoodAvailability is admission-only, while
    266   marker-free generic and mixed-marker NIP-99 events cannot be mislabeled as
    267   operational contracts.
    268 - Verified Profile admission binds a signed exact kind-`0` envelope to the
    269   tolerant metadata projection, accepts standard tagless events, and exposes
    270   deterministic equal-time lowest-id replacement vectors.
    271 - Strict authored Update, PhotoUpdate, and Ask types emit deterministic kind-`1`
    272   wire parts. Photo and Ask media require byte-verified Blossom image
    273   descriptors, exact ordered NIP-92 metadata, bounded nonzero fields, and
    274   same-digest approved fallback URLs.
    275 - Raw signed kind-`1` conformance vectors prove signature-gated profile
    276   admission, thread-candidate exclusion, classifier precedence, tolerant
    277   metadata retention, and stable rejection codes. Operation-owned vectors also
    278   execute every typed post authoring, projection, and admission function and
    279   compare complete deterministic outputs.
    280 - Raw signed NIP-10 vectors execute marked direct and nested Replies, marked
    281   supplemental citations, deprecated positional empty-marker author hints,
    282   malformed middle-citation tolerance, participant and relay validation,
    283   classifier precedence, signature-gated admission, and stable invalid-case
    284   codes through the public owning APIs.
    285 - The fixed 114-case NIP-22 corpus executes all three governed Comment
    286   operations with complete authored wire, verified projection, diagnostic,
    287   admission, Unicode, precedence, and exact resource-limit expectations.
    288   Projection and admission inputs are self-contained signed event JSON, and
    289   the packaged fixture is byte-identical to the canonical contract vector.
    290 - Generic NIP-01 coordinates now validate canonical
    291   `kind:pubkey:identifier` values with the correct replaceable and addressable
    292   kind rules. Strict NIP-09 authoring emits deterministic kind-`5` `e`, `a`,
    293   and derived `k` tags, while tolerant verified projection preserves advisory
    294   diagnostics and admission keeps the projection bound to its
    295   signature-verified envelope. Fixed contract-owned conformance vectors cover the
    296   authored, projection, admission, and resource-boundary operations.
    297 - NIP-09 deletion requests now enter signing and client publication through a
    298   sealed typed builder with no raw kind, content, or tag mutation. This surface
    299   creates and transports a request only; it provides no target lookup,
    300   authorship decision, deletion authorization, store mutation, relay-effect,
    301   or deletion-effect semantics.
    302 - NIP-09 suppression evaluation is now a separate pure operation over one
    303   signature-verified candidate and admitted requests. It enforces same-author
    304   direct-event and inclusive address-cutoff rules, keeps kind `5` immune,
    305   ignores advisory kinds, returns canonical evidence independent of input
    306   order, and never mutates raw events or storage.
    307 - The NIP-09 reconciliation-v1 manifest and executable event-store result
    308   vector pin migration `0002`, registry-v7 inventory, semantic vector inputs,
    309   and the frozen verification, admission, head-selection, and suppression
    310   source graph.
    311 - Event-store NIP-09 migration now bounds every retained raw-source text field
    312   and row count through matching preflight, in-lock, and paged-loader checks.
    313   Capacity failure is typed and atomic, and exact-target indices avoid cloning
    314   request payloads or scanning unrelated requests per candidate head. Rebuild
    315   tickets can commit at their captured raw high-water while later events remain
    316   available for ordinary catch-up. Schema opens validate every applied hook,
    317   and composed callers can reserve the SQLite writer with
    318   `begin_write_transaction` before reading and ingesting in one transaction.
    319   Borrowed-transaction ingests use nested savepoints so a failed call cannot
    320   leave partial event-store writes available for the caller to commit.
    321 
    322 ### Removed
    323 
    324 - The duplicate private operational listing parser in `radroots_trade` was
    325   removed; trade validation now consumes the canonical event codec.
    326 - The ambiguous `listing` source modules and public compatibility aliases were
    327   removed. Consumers must migrate to the Classified Listing protocol names or
    328   Operational Listing product names according to the API's responsibility.
    329 - The public operational-listing JSON wire-parts authoring helper was removed;
    330   product authoring uses the canonical Markdown wire-parts path.
    331 - Legacy calendar event models and permissive calendar tag-builder authoring
    332   paths were removed.
    333 - Direct `RadrootsProfile` draft encoding and the identity profile publisher were
    334   removed in favor of the validated authored-profile boundary.
    335 - The `radroots_identity/profile` Cargo feature was removed with its embedded
    336   legacy Profile projection.
    337 - Replica sync no longer synthesizes Profile events from lossy stored
    338   projections. Its transfer protocol is now version `2`, and request JSON
    339   containing the removed `include_profiles` option is rejected.
    340 - `RadrootsNostrClient` no longer implicitly dereferences to the upstream SDK
    341   client. Narrow client operations and the explicit ownership bridge remain.
    342 - `RadrootsNostrSignerBackend` no longer accepts a raw `nostr::EventBuilder`;
    343   callers that implement standard external signer protocols must supply the
    344   protocol's unsigned event explicitly.
    345 - Permissive `RadrootsPost` tag authoring, the free-form Nostr post builder, and
    346   the generic net custom publisher were removed. Product-root publication now
    347   requires one of the strict authored Update, PhotoUpdate, or Ask states.
    348   Generic kind-1 authoring is no longer available through the generic protocol
    349   builder; non-product interoperability remains available only for
    350   non-reserved kinds.
    351 - The permissive post-reply builder and raw-string net reply publisher were
    352   removed. Reply signing and client publication now require the typed NIP-10
    353   Reply boundary.
    354 - The legacy `RadrootsComment` DTO/Serde model, permissive Comment
    355   encode/decode modules, and their public functions were removed. Comment
    356   authoring now requires `RadrootsAuthoredNip22Comment`, while inbound use must
    357   pass through verified projection or admission.
    358 - The Reply-owned `RadrootsNip10RelayHint` name was removed. Callers must use
    359   the shared `RadrootsNostrRelayHint` type for canonical Nostr tag relay hints.
    360 
    361 ### Compatibility
    362 
    363 - Callers that previously passed out-of-range `u32` kinds to Nostr builders or
    364   job decoders now receive typed range errors instead of truncated kinds.
    365 - Identity JSON containing the removed embedded `profile` projection is now
    366   rejected, including the nested public-profile form, instead of being loaded
    367   and later rewritten without that field.
    368   Migrate the value to a signed kind-`0` metadata event before rewriting the
    369   identity file.
    370 - Replica-store backups and export manifests now record a stable schema
    371   compatibility version instead of package SemVer. Existing backups stamped by
    372   `0.1.0-alpha.2` remain restorable because this release does not change their
    373   stored schema.
    374 - Persisted frozen drafts with event-contract registry versions `1` through
    375   `6` are rejected and must be reconstructed against registry version `7`;
    376   strict Profile plus typed and read-only post contracts can no longer be
    377   reconstructed as generic drafts.
    378 - Generic builder signing and client publication reject kind `1111` before
    379   signer access. Product Comment publication must use the sealed NIP-22
    380   builder; relaying an already signed event remains a generic transport
    381   operation without a typed authoring claim.
    382 - Generic builder signing and client publication reject every kind `5` before
    383   signer access. Product deletion-request publication must use the sealed
    384   NIP-09 builder; externally supplied unsigned events, NIP-46 signing, and
    385   relaying an already signed event remain low-level interoperability operations
    386   without a typed authoring or deletion-effect claim.
    387 - This breaking capsule revision must not be pinned or published through
    388   downstream product clients until `radroots_app_rt` is migrated, generated FFI
    389   bindings are rebuilt, and downstream compile and contract qualification pass.
    390 - `radroots_event_from_nostr` now returns `Result<RadrootsEventEnvelope,
    391   RadrootsEventEnvelopeError>`; callers must handle hostile or oversized SDK
    392   events explicitly.