docs: de-link spike findings from spike/ code (moved to private repo)
This commit is contained in:
parent
2d4dec5304
commit
5b64fe14b3
1 changed files with 25 additions and 23 deletions
|
|
@ -1,9 +1,9 @@
|
|||
# Spike — Block 2 (social layer) de-risking findings
|
||||
|
||||
*Throwaway research spike. Language: English (findings), per code convention.
|
||||
Code lives in [`spike/block2_spike/`](../../spike/block2_spike/) and is marked
|
||||
throwaway — **not production, not on the pub workspace, no deps added to Block
|
||||
1**. This document is the deliverable: what we learned, the risks, and a
|
||||
The throwaway spike code (`spike/block2_spike/`) has been moved out of this
|
||||
public repo and preserved privately — it was **not production, not on the pub
|
||||
workspace, no deps added to Block 1**. This document is the deliverable: what we learned, the risks, and a
|
||||
recommendation on whether/how to take on the social round (Phase 3).*
|
||||
|
||||
> **Status: this is a spike, not a green light to build Block 2.** CLAUDE.md and
|
||||
|
|
@ -34,7 +34,7 @@ See "How to run" at the end.
|
|||
|
||||
**Result: works, deterministic, one-way. This unblocks "one identity, one backup".**
|
||||
|
||||
- Implemented [`NostrKey.deriveFromSeed`](../../spike/block2_spike/lib/src/nostr_key.dart):
|
||||
- Implemented `NostrKey.deriveFromSeed`:
|
||||
`HKDF-SHA256(rootSeed, info: "org.comunes.tane/nostr/secp256k1/v1")` → reduce
|
||||
to a valid secp256k1 scalar `d ∈ [1, n-1]` by rejection (bump a counter in the
|
||||
HKDF info on the astronomically-rare miss, so the result stays a pure function
|
||||
|
|
@ -80,13 +80,13 @@ trust do NOT fit behind the same interface — they share a *connection*, not a
|
|||
*contract*.**
|
||||
|
||||
### The seam works (offers)
|
||||
- [`OfferTransport`](../../spike/block2_spike/lib/src/offer_transport.dart) =
|
||||
- `OfferTransport` =
|
||||
`publish(Offer)` / `discover(DiscoveryQuery)` / `retract(id)`. The Nostr
|
||||
NIP-99 backend ([`NostrOfferTransport`](../../spike/block2_spike/lib/src/nostr_offer_transport.dart)
|
||||
+ [`Nip99Codec`](../../spike/block2_spike/lib/src/nip99.dart)) sits entirely
|
||||
NIP-99 backend (`NostrOfferTransport`
|
||||
+ `Nip99Codec`) sits entirely
|
||||
behind it. A second backend (ActivityPub/FEP-0837) could replace it without
|
||||
the domain noticing.
|
||||
- [`Offer`](../../spike/block2_spike/lib/src/offer.dart) is agnostic by
|
||||
- `Offer` is agnostic by
|
||||
construction: a chosen *summary* + coarse geohash, **no FK into seed tables,
|
||||
no full inventory, no exact address** — exactly the Offer↔Lot split
|
||||
[sharing-model.md](sharing-model.md) §2 and
|
||||
|
|
@ -114,14 +114,14 @@ manageable**:
|
|||
private encrypted DM vs. assert/read a signed certification. Forcing DMs and
|
||||
certifications behind `OfferTransport.publish/discover` would overload it.
|
||||
- **Recommendation — now demonstrated in code, not just asserted:**
|
||||
[`NostrConnection`](../../spike/block2_spike/lib/src/nostr_connection.dart) is
|
||||
`NostrConnection` is
|
||||
**one shared** socket + key + sign + REQ/EOSE lifecycle, and **all three thin
|
||||
interfaces sit on top of the same instance** —
|
||||
[`OfferTransport`](../../spike/block2_spike/lib/src/nostr_offer_transport.dart)
|
||||
`OfferTransport`
|
||||
(NIP-99),
|
||||
[`MessageTransport`](../../spike/block2_spike/lib/src/nostr_message_transport.dart)
|
||||
`MessageTransport`
|
||||
(NIP-17) and
|
||||
[`TrustTransport`](../../spike/block2_spike/lib/src/nostr_trust_transport.dart)
|
||||
`TrustTransport`
|
||||
(custom WoT). The trust test even runs offer discovery and trust annotation
|
||||
over one connection. This is the shape to lift into `commons_core`: shared
|
||||
connection, per-concern contract. Trying to make `OfferTransport` also carry
|
||||
|
|
@ -139,7 +139,7 @@ that whole happy path now runs — what's left is production hardening (below).
|
|||
**Result: the flow works end to end. The real risk is NIP maturity/ecosystem,
|
||||
not the mechanics.**
|
||||
|
||||
- Built a hermetic in-process [`MiniRelay`](../../spike/block2_spike/lib/src/mini_relay.dart)
|
||||
- Built a hermetic in-process `MiniRelay`
|
||||
(NIP-01 subset: EVENT/REQ/EOSE/CLOSE, filter by `kinds`/`authors`/`#g`,
|
||||
addressable-event replacement for kind 30402). No network → CI-safe, no flaky
|
||||
public-relay dependency.
|
||||
|
|
@ -183,13 +183,13 @@ The plan ([network-trust.md](network-trust.md) §4) calls messaging "grande" and
|
|||
[open-decisions.md](open-decisions.md) §D.3 singled it out as the tightest
|
||||
coupling to Nostr. So the spike built it rather than hand-waving:
|
||||
|
||||
- **NIP-44 v2 encryption** ([`Nip44`](../../spike/block2_spike/lib/src/nip44.dart)):
|
||||
- **NIP-44 v2 encryption** (`Nip44`):
|
||||
secp256k1 ECDH → HKDF conversation key → ChaCha20 + HMAC-SHA256 with
|
||||
length-hiding padding. Conversation key is symmetric (A→B == B→A, tested); a
|
||||
wrong key cannot decrypt (throws, tested); short messages pad to the same
|
||||
bucket so ciphertext length doesn't leak plaintext length (tested).
|
||||
- **NIP-17 / NIP-59 gift-wrap onion**
|
||||
([`NostrMessageTransport`](../../spike/block2_spike/lib/src/nostr_message_transport.dart)):
|
||||
(`NostrMessageTransport`):
|
||||
rumor (kind 14, unsigned) → seal (kind 13, signed by sender, NIP-44 to
|
||||
recipient) → gift wrap (kind 1059, signed by a **throwaway ephemeral key**,
|
||||
NIP-44 to recipient).
|
||||
|
|
@ -223,12 +223,12 @@ There is no settled NIP for a web of trust, so — exactly as
|
|||
anticipates — the spike models **its own WoT, Duniter-compatible**, over Nostr:
|
||||
|
||||
- **Certifications as events**
|
||||
([`NostrTrustTransport`](../../spike/block2_spike/lib/src/nostr_trust_transport.dart)):
|
||||
(`NostrTrustTransport`):
|
||||
a custom addressable kind (30777) keyed by (issuer, `d`=subject), so one live
|
||||
"A vouches for B" per pair; re-certifying renews, revoking replaces (tested).
|
||||
Certifications expire (Ğ1 semantics) and are public (like the on-chain Ğ1 WoT).
|
||||
- **The membership rule is pure and separately tested**
|
||||
([`WebOfTrust`](../../spike/block2_spike/lib/src/web_of_trust.dart)) — the
|
||||
(`WebOfTrust`) — the
|
||||
`commons_core`-worthy piece: Duniter's two rules, **N certifications from
|
||||
existing members** (sigQty) and **within distance D of the bootstrap
|
||||
referents** (stepMax), iterated to a fixpoint (becoming a member can push
|
||||
|
|
@ -263,8 +263,9 @@ entity, and optionally importing the on-chain Ğ1 WoT (level 3) as a trust sourc
|
|||
([open-decisions.md](open-decisions.md) §D.1, §D.6). That is what should drive
|
||||
the Phase-3 estimate and the funding ask.
|
||||
4. **Do not start Block 2 from this spike.** It is throwaway research code (not
|
||||
vector-verified, no offline delivery, no persistence, single relay). Delete
|
||||
`spike/block2_spike/` once these findings are absorbed. The funded social
|
||||
vector-verified, no offline delivery, no persistence, single relay). The
|
||||
`spike/block2_spike/` code has been moved out of this public repo (preserved
|
||||
privately) now these findings are captured. The funded social
|
||||
round should **rebuild on vetted client libraries in `commons_core`**, using
|
||||
the shapes proven here — one `NostrConnection`, three interfaces, the pure
|
||||
`WebOfTrust` rule — and spend its risk budget on hardening and bootstrap, not
|
||||
|
|
@ -283,11 +284,12 @@ entity, and optionally importing the on-chain Ğ1 WoT (level 3) as a trust sourc
|
|||
|
||||
## How to run
|
||||
|
||||
The throwaway spike code has been moved out of this public repo and is preserved
|
||||
privately; nothing here was wired into `app_seeds` or `commons_core`'s production
|
||||
graph, and the Block 1 suite is untouched. For the record, it ran as:
|
||||
|
||||
```sh
|
||||
cd spike/block2_spike
|
||||
cd spike/block2_spike # in the private archive
|
||||
dart pub get
|
||||
dart test # derivation · privacy · roundtrip · messaging · trust · web_of_trust (30 tests)
|
||||
```
|
||||
|
||||
Nothing here is wired into `app_seeds` or `commons_core`'s production graph; the
|
||||
Block 1 suite is untouched.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue