Skip to content

S15/S16 invariants + L402 compat + ROADMAP#1

Merged
Danny-Devs merged 7 commits into
mainfrom
danny/invariants-s15-s16-and-roadmap
Apr 22, 2026
Merged

S15/S16 invariants + L402 compat + ROADMAP#1
Danny-Devs merged 7 commits into
mainfrom
danny/invariants-s15-s16-and-roadmap

Conversation

@Danny-Devs
Copy link
Copy Markdown
Contributor

Summary

Two additive changes that together land the April 2026 Wave 4 Council output plus the third pillar of the "universal read" positioning thesis.

Invariants S15/S16 + ROADMAP (commit 780c8c1)

  • S15 Mid-Session Signer Rotation — long-running schemes (stream, prepaid, escrow, multi-phase unlock) bound to mandate/shared-object capabilities, not signer pubkeys. Sharpest case: Sui zkLogin ephemeral-key cycling now explicitly tolerated.
  • S16 Protocol Version Binding — version + scheme digest bound into the signed payload (Sui PTB prepends assert_protocol_version), not only transport headers. Closes semantic-downgrade attacks across scheme amendments.
  • Disciplined delta analysis (ADR-010 §Context) rejects three redundant candidates (atomicity, auditability, cross-process idempotency) and one out-of-scope (revocability), preserving the "invariants don't inflate" principle.
  • New ROADMAP.md — first public roadmap; parks Privacy Scheme as P1, documents v0.6.x/v0.7.0 sequencing, lists non-goals.

L402 compat-layer (commit ca61454, DAN-344)

  • New sub-path export s402/compat-l402 consuming Lightning Labs L402/LSAT challenges as native s402 types. With x402 + MPP already shipped, s402 is now a strict superset of every 402 dialect in production.
  • parseWwwAuthenticateL402, decodeBolt11Summary (HRP-only, BigInt msat math, pico-BTC divisibility check), fromL402Challenge (macaroon + invoice surfaced under extensions.l402 for retry construction).
  • 29 unit tests across all four multiplier classes (m/u/n/p), all four networks (mainnet/testnet/regtest/signet), LSAT/L402 alias handling, amountless-invoice rejection, malformed HRPs.
  • New docs/positioning.md — three-pillar USP (expressiveness / universal read / on-chain enforcement) as single source of truth for landing/pitch/grant copy.
  • New docs/guide/upgrade-l402.md — migration guide with BOLT-11 multiplier reference table.

Version bumps (commits 226dfd9, 1f056ac) — demo-api bumped to s402@^0.6.0 with Accept-Payment negotiation wired; @sweefi/server 0.1.0 → 0.1.2 registry sync.

Compatibility

  • Purely additive. No changes to existing wire types, scheme interfaces, conformance vectors, or the 13 shipped test vectors.
  • S7 preserved. No chain-specific imports in typescript/src/. L402 uses abstract lightning:* network identifiers, not a Lightning SDK.
  • New sub-path exports sit alongside s402/compat (x402) and s402/compat-mpp (Stripe/Tempo). Root entry pulls no compat bundle.
  • Existing 0.6.x consumers require zero code changes.

Test plan

  • Unit tests: 29 L402 tests in typescript/test/compat-l402.test.ts, all multiplier + network + alias + edge-case paths
  • CHANGELOG, tsdown entry, and package.json exports all include compat-l402
  • CI: typecheck + full test suite + S7 boundary test pass
  • Self-review on PR page for archaeology

Linear

  • ADR-010 — Wave 4 Council output (April 2026), no single ticket (roadmap-level work)
  • DAN-344 — L402 compat in parent "Universal 402 Absorption" project; siblings DAN-345 (MPP Session), DAN-346 (MPP write), DAN-347 (AP2), DAN-348 (IETF), DAN-349 (ERC-7824)

Danny-Devs and others added 4 commits April 19, 2026 23:53
Matches the current protocol version and exercises the Accept-Payment
header round-trip (parse incoming preferences → selectBestScheme →
advertise server-side support back via formatAcceptPayment) that
landed in the core package. Also expands CORS allow/expose lists to
cover the accept-payment header name.

Typecheck clean.
0.1.1 was published to npm at some point without a corresponding
repo commit, leaving package.json stuck at 0.1.0. Since then two
meaningful source commits landed (HTTP hygiene bundle 85e8246, nosniff
header 3350a82), so jumping straight to 0.1.2 — the next publish
carries real content beyond whatever 0.1.1 contained.
…— DAN-344

s402 is now a strict superset of every 402 dialect in production: x402
(Coinbase), MPP (Stripe/Tempo), and L402 (Lightning Labs). Absorption is
codified as a standing commitment in the new Universal 402 Absorption
Linear project.

## s402/compat-l402 (new sub-path export)

- parseWwwAuthenticateL402 — RFC 9110 auth-params parser; accepts both
  L402 and legacy LSAT auth-scheme names (canonicalized to L402)
- decodeBolt11Summary — partial BOLT-11 decoder over the human-readable
  part only; extracts network (mainnet/testnet/regtest/signet) + amount
  via m/u/n/p multiplier arithmetic (BigInt); rejects pico-BTC amounts
  not divisible by 10
- fromL402Challenge — translates to s402PaymentRequirements with
  scheme="exact", asset="lightning:msat", sentinel payTo="lightning:invoice"
  (real destination lives inside the BOLT-11 invoice); macaroon + invoice
  surfaced under extensions.l402 for retry construction; rejects
  amountless invoices as spec violations

29 unit tests cover all four multiplier classes, all four networks,
LSAT/L402 alias handling, malformed HRPs, and end-to-end header-to-
requirements flows. 985 tests total, all green.

## Positioning (new canonical doc)

docs/positioning.md establishes the three-pillar USP as the single
source of truth for landing copy, pitch, and grant apps:

1. Expressiveness — six schemes (Exact, Upto, Prepaid, Escrow, Stream,
   Unlock); three have no equivalent in any competing protocol
2. Universal read — one server speaks every 402 dialect on the wire;
   compat layers live in sub-path exports with zero core pollution
3. On-chain enforcement — every invariant is a Move contract, not a
   server policy

## Scope (intentionally deferred)

- L402 write path (requires a Lightning node; belongs in Aperture, not
  a wire-format library)
- Macaroon caveat decoding (opaque passthrough)
- Full BOLT-11 tagged-field decoding (Lightning wallets already do this)
- BOLT-12 offers (spec still evolving)

## Linear

New project: Universal 402 Absorption. Child issues DAN-344 (L402,
in progress), DAN-345 (MPP Session), DAN-346 (MPP write path), DAN-347
(Google AP2 research), DAN-348 (IETF reference impl path), DAN-349
(ERC-7824 watch).

## Compatibility

Purely additive. No changes to existing types, wire format, or
conformance vectors. 0.6.x consumers require no code changes. New
sub-path export sits alongside s402/compat (x402) and s402/compat-mpp.
…n binding) via ADR-010

Council-driven delta analysis (April 2026 Wave 4 review) identified five
candidate invariants. Disciplined audit against existing S1-S14 and ADRs
006/007/008/009 narrowed the set to two genuine gaps:

- S15 Mid-Session Signer Rotation: long-running schemes (stream, prepaid,
  escrow, multi-phase unlock) bound to mandate/shared-object capabilities,
  not signer pubkeys. Sharpest case: zkLogin ephemeral key cycling.

- S16 Protocol Version Binding: version + scheme digest bound into the
  signed payload (Sui PTB prepends assert_protocol_version), not only in
  transport headers. Closes semantic-downgrade attacks across scheme
  amendments.

Dropped as redundant:
- Atomicity (covered by S8 + ADR-007 txBinding)
- Auditability (covered by S11 + ADR-007 envelope)
- Cross-process idempotency (covered by S5 + ADR-007 Idempotency-Key)

Dropped as out-of-scope:
- Revocability (Swee Mandate Move layer, not s402 wire)

Small augmentations to existing invariants:
- S5: note on cross-process dedup via ADR-007 Idempotency-Key.
- S8: note on S8 x S15 interaction (per-tx vs per-session).

Also: new ROADMAP.md formally parks the Privacy Scheme as P1, triggered by
Sui privacy-primitive maturation; documents v0.6.0/0.6.1/0.6.2/0.7.0
sequencing; lists non-goals to prevent scope creep.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
s402-docs Ready Ready Preview, Comment Apr 22, 2026 5:01am

Copy link
Copy Markdown
Contributor Author

@Danny-Devs Danny-Devs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Retracted — review moved offline with maintainer.)

Two coupled changes. Tests (988) + typecheck + build all clean.

## Reorganization — flat files to src/compat/ subdirectory

Before: src/compat.ts, src/compat-mpp.ts, src/compat-l402.ts
After:  src/compat/x402.ts, src/compat/mpp.ts, src/compat/l402.ts

Matching sub-path exports rewritten to s402/compat/{x402,mpp,l402}.
The old unlabeled s402/compat (x402-by-default) is gone — x402 is now
explicit, which is the honest naming. Pre-1.0 minor bump (0.6.x → 0.7.0)
licenses the rename; no backward-compat aliases shipped.

Git rename detection preserves blame. Internal relative imports updated
to ../X.js. All doc examples + source comments rewritten.

## Hardening — compat-l402

1. expiresAt now stamped on L402-derived requirements. Conservative
   60s window because the BOLT-11 expiry tag lives in tagged-fields
   past the `1` separator (out of scope for the partial HRP-only decoder).
   Keeps S1 (stale payment rejection) load-bearing against stale-invoice
   replay. Tradeoff: long-lived invoices rejected after 60s → one extra
   402 re-fetch, not a payment failure.

2. Canonical BOLT-11 signet prefix `lntbs` now recognized (current spec,
   core-lightning, recent LND). Legacy `lnsb` prefix retained as alias
   for older LND emissions. Regex alternation reordered (longest first)
   to prevent shadow-matching.

3. HRP_PATTERN gained a clarifying comment about the intentional
   HRP-only validation scope.

## Tests

+3 in compat-l402.test.ts (expiresAt fresh-stamp, expiresAt window,
canonical-signet vs legacy-signet aliasing). 32 L402 tests total.
All import paths updated across 5 test files.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Node 18 reached end-of-life April 2025. envelope.ts's computeTxBinding
relies on globalThis.crypto.subtle which is only available unflagged in
Node 19+, causing CI to fail on the Node 18 matrix slot. The Node 18
slot was masking what would otherwise be green CI on 20 + 22.

- .github/workflows/ci.yml: matrix [18, 20, 22] -> [20, 22]
- typescript/package.json: engines.node ">=18" -> ">=20"
- typescript/README.md, README.md, docs/guide/quickstart.md,
  docs/guide/tutorial.md: update Node requirement text
- CHANGELOG: log the breaking minimum-Node bump under v0.7.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Follow-up to 24ff521 — that commit landed the engines.node bump and
docs updates but the .github/workflows/ci.yml edit silently didn't
persist (Edit tool reported success but file was unchanged on disk;
caught on post-commit verification). This commit lands the matrix
change [18, 20, 22] -> [20, 22] for real.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Danny-Devs Danny-Devs merged commit cbc2dd4 into main Apr 22, 2026
10 checks passed
@Danny-Devs Danny-Devs deleted the danny/invariants-s15-s16-and-roadmap branch April 22, 2026 05:07
@Danny-Devs Danny-Devs mentioned this pull request Apr 22, 2026
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant