The de-risking spike validated the whole social happy path, so Block 2 moves
from "do NOT start" to STARTED. Records the build order (transport foundation in
commons_core first, on the vetted pure-Dart nostr lib) and marks open-decisions
D.3/D.7 as resolved by the spike.
Adds TrustTransport as the third interface on the shared NostrConnection,
completing the social-layer happy path in the spike:
- WebOfTrust: pure, Flutter-free Duniter membership rule (N certs from members +
within distance D of bootstrap referents), iterated to a fixpoint. The
commons_core-worthy piece; TDD'd (threshold, distance cutoff, transitive
growth, expired/revoked/self exclusion).
- NostrTrustTransport: certifications as a custom addressable kind (30777,
keyed by issuer+subject) — certify renews, revoke replaces, certs expire.
- Trust filters spam (network-trust §2): seeds certify Alice; Eve stays
uncertified; Bob discovers both offers and annotates authors — Alice known,
Eve unknown — all over ONE shared connection.
Findings updated: WoT risk High -> Medium (policy/bootstrap, not feasibility);
overall scope Medium-High -> Medium — all three transport contracts now proven.
30 tests green, analyzer clean, Block 1 untouched.
Extends the Block 2 spike to attack the highest-risk unbuilt piece (private
messaging) and to prove the Q2 architecture recommendation with running code:
- NostrConnection: one shared socket+key+sign+REQ/EOSE lifecycle. Refactored
NostrOfferTransport onto it; added NostrMessageTransport — two thin contracts
on ONE connection (the 'one connection, three interfaces' shape).
- NIP-44 v2 encryption (secp256k1 ECDH -> ChaCha20 + HMAC, length-hiding pad).
- NIP-17/NIP-59 gift-wrap: rumor(14) -> seal(13) -> wrap(1059, ephemeral key).
Alice->Bob DM round-trips through the relay: encrypted, sender authenticated,
and metadata-private (relay/eavesdropper sees only ciphertext, an ephemeral
author and the recipient p-tag — Alice stays hidden).
Findings updated: NIP-17 risk drops Medium-High -> Medium (hardening, not
feasibility); next de-risking target is the web of trust. NIP-44 not yet
vector-verified (noted). 20 tests green, analyzer clean, Block 1 untouched.
Throwaway research spike (spike/ branch, outside pub workspace, no prod deps
touched). Validates the open Block 2 decisions before committing a funded round:
1. Deterministic one-way secp256k1 (Nostr) key derived from the Ğ1 root seed
via HKDF — user still backs up ONE thing. Reproducible + signs (BIP340).
2. OfferTransport abstraction over Nostr NIP-99 (kind 30402); Offer stays
inventory/location-agnostic, geohash coarsened on the wire (tested).
3. publish->discover-by-geohash proven end-to-end against an in-process
hermetic mini-relay (~34ms round-trip).
Findings + risks + recommendation in docs/design/spike-block2-findings.md.
Block 1 suite untouched. 14 tests green, analyzer clean.
Interchange export/import for Phase 1 (data-model §7):
- JSON: canonical, versioned envelope (formatVersion 1) with all sync
metadata verbatim, photos embedded as base64, tombstones excluded.
Species are re-resolved on import by scientific name (catalog ids are
per-install). Reader tolerates unknown fields/enum values (§5.2) and
rejects newer format versions with a clear error.
- CSV: export-only spreadsheet flatten, one row per lot, RFC 4180
escaping, never any photo bytes.
- Import merges by UUIDv7 id in one transaction: insert-if-unknown
preserving original stamps, last-writer-wins by packed HLC for known
mutable rows, append-only movements; afterwards the local clock
receiveEvent()s the newest imported stamp so it never runs behind.
- Settings gains a Backup section (export CSV/JSON, import JSON with
confirmation); file dialogs behind a FileService interface backed by
file_picker (MIT).
- Tests: codec round-trip and tolerance, reconciler LWW, repository
export→import round-trip (fresh DB, idempotent re-import, newer-local
wins, clock monotonicity, species re-resolution), backup widget flows.
Expand LotType from {seed, plant} to six append-only forms (seed,
seedling, plant, tree, bulb, cutting) and add an optional Presentation
attribute (pot/tray/plug/bareRoot/rootBall) kept separate from quantity
so 'how many' and 'in what packaging' never conflate.
Add attachments.sortOrder so the cover photo is the lowest-ordered one,
enabling reordering from the full-screen viewer. Expand QuantityKind
with the new plant-aware forms.
Migrations are additive (v1→v5 all covered by migration_test); enum
values are stored by name and appended only, keeping CRDT sync safe.
Visual pass toward docs/mockups (06 inventory, 07 item):
- Bundle the seedks icon font (chars a–k → seed pictograms: jar, packet, spoon…)
and a SeedGlyph/QuantityKindIcon helper.
- Green app bar + pale-green canvas theme (buildTaneTheme).
- Inventory list: rounded-square photo thumbnail or green initial avatar, bold
title, scientific-name subtitle, trailing edit pencil, styled category
headers, rounded search field, seed-glyph empty state.
- Quantity selectors (quick-add + add-lot) show the seed pictogram + word;
detail lot lines use the kind's glyph.
- Detail header restyled to mockup 07: category link + scientific name on the
left, photo on the right.
watchInventory now also returns the linked species' scientific name (subtitle).
37 app tests green; seedks font verified in the Linux asset bundle.