mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-12 01:07:46 +00:00
docs(clink): record interop review + spec-conformance pass results
https://claude.ai/code/session_01NM2TyJtosLdY5ycjyabSRS
This commit is contained in:
@@ -244,3 +244,55 @@ against a real CLINK service is not automated (needs a device or a
|
||||
mock/live service). Feasible later via quartz's in-process relay server
|
||||
(`nip01Core/relay/server/`) plus a mock CLINK responder; flagged but not
|
||||
built.
|
||||
|
||||
---
|
||||
|
||||
## Interop review & spec-conformance pass (2026-06-10)
|
||||
|
||||
Reviewed against the whole `shocknet/CLINK` ecosystem (Lightning.Pub, clink-sdk,
|
||||
ShockWallet, Zeus, Stacker News, bridgelet, clinkme.dev) and re-audited every
|
||||
spec file line-by-line against the code. **Verdict: the consume-only
|
||||
payer/requestor role is conformant and interoperable; no real correctness bugs.**
|
||||
|
||||
**Interop fixes shipped:**
|
||||
1. Manage `details` single-object responses parse (Jackson
|
||||
`ACCEPT_SINGLE_VALUE_AS_ARRAY`) — Lightning.Pub returns a bare object for
|
||||
create/update/get, an array only for `list`.
|
||||
2. `NOffer.encode()` always emits the price-type TLV (3); decode defaults an
|
||||
absent/unknown type to SPONTANEOUS. The SDK + bridgelet decoders throw on a
|
||||
missing TLV 3, so omitting it made our pointers undecodable by JS consumers.
|
||||
3. `Nip05Parser.parseClinkOffer` accepts bridgelet's flat-string shape as well
|
||||
as the spec's per-name map.
|
||||
4. Offer receipts are a parseable primitive (`OfferEvent.createReceipt` /
|
||||
`decryptReceipt`, `OfferClient.parseReceipt`, `OfferReceipt.isOk`).
|
||||
5. `ClinkOfferPayer` signs offer requests with an ephemeral key (privacy parity
|
||||
with the SDK/Zeus/Stacker News). Debits keep the persistent account key
|
||||
(budgets need a stable app identity).
|
||||
|
||||
**Conformance hardening shipped:** `NDebit.parse` rejects a non-32-byte k1;
|
||||
`DebitClient.requestBudget` validates `frequency.unit ∈ {day,week,month}`;
|
||||
`OfferClient` caps `description` at 100 chars; `DebitResponse.failureDetail()`
|
||||
surfaces GFY `range`/`retry_after` in the debit zap error path.
|
||||
|
||||
**New tests:** `ClinkWireShapeTest` (golden JSON payloads from the public-domain
|
||||
specs), a clink-demo/SDK canonical `DEFAULT_NOFFER` vector, plus regressions for
|
||||
each fix above.
|
||||
|
||||
**Three "CRITICAL" review findings were verified FALSE — do NOT re-chase them:**
|
||||
- *Offer price encoding for ≥2³¹ sats* is correct: `addInt` writes the low 32
|
||||
bits, which are bit-identical to the unsigned 4-byte BE (proven by
|
||||
`offerLargePriceRoundTripIsUnsigned`, 3e9 sats). Only ≥2³² loses data, which
|
||||
the spec's 4-byte field can't represent anyway.
|
||||
- *Parser "wrongly accepts `nostr:`/`lightning:` wrappers"* is not a violation:
|
||||
the MUST-NOT-wrap rule governs producing QR (our `encode()` is bare); lenient
|
||||
decode is Postel-legal.
|
||||
- *Manage "create shape deviation"* — the spec's inline-create example is the
|
||||
outlier; Lightning.Pub/SDK/clink-demo all use nested `offer.fields` for create,
|
||||
which we match.
|
||||
|
||||
**Remaining non-bugs (intentional / out-of-role):** we don't reject responses
|
||||
lacking `clink_version` (Lightning.Pub omits it — rejecting breaks interop); the
|
||||
offer Payment Receipt UI subscription is unwired (primitive ships); `clink_debit`
|
||||
discovery and the unrestricted-access debit request are creditor/app-side
|
||||
features outside the consume-only role; noffer TLV 5 currency is dormant
|
||||
(unimplemented by the SDK and Lightning.Pub too).
|
||||
|
||||
Reference in New Issue
Block a user