Skip to content

Spec conformance ​

kernl conforms to specifications it does not own. This page says which ones, what "upstream first" means in practice, and how a gap is recorded.

Authority ​

AreaAuthorityLocal copy
Shell–applet protocolNIP-5D, nostr-protocol/nips PR #2303none
NAP domains (relay, outbox, dm, resource, …)napplet/napsnone
Wire types and dispatch@napplet/core, pinned >=0.37.0 <0.38.0the installed package
Shell compositionkehto source, @kehto/* at the pinned rangesthe installed packages
Event layerapplesauce v7, applesauce.buildthe installed packages
Messaging protocolsNIP-17, NIP-04, the nostr double-ratchet draft, as named in each provider's specificationnone

kernl keeps no local copy of a specification text. A copy drifts; a link does not. When the PR or a NAP document changes, the behaviour changes in kernl in a pull request that cites the clause.

Upstream first ​

When kernl needs something a specification or an upstream package does not provide, the order is:

  1. Compose it from what exists. Most of kernl is this: the guard composes @kehto/firewall's evaluate(), the restrictive posture composes resolveEnvironment and aclState.grant.
  2. Propose it upstream. An issue or pull request on kehto/web, napplet/naps or nostr-protocol/nips, as appropriate. The four kehto gaps kernl has found, filed upstream as kehto/web #397–#400, are listed in Alpha status.
  3. Implement it locally with a recorded gap. Only when 1 is impossible and 2 is pending. The local implementation sits behind an interface, cites the upstream issue, and is removed when upstream lands.

kernl never re-implements a kehto primitive because it was easier than reading kehto's source, and never invents wire format. When a NAP is ambiguous, kernl prefers an upstream issue over a guess and records the ambiguity next to the code.

What conformance is checked by ​

  • Gherkin scenarios in packages/*/features/ for every protocol-visible behaviour, named after the clause they implement where one exists.
  • Review. A change that touches an envelope shape, a domain's semantics or the handshake cites the clause in its description. A reviewer checks the clause, not the summary.

@napplet/conformance (envelope validators per NAP domain, manifest validation and the reference mock shell's expectations of a host) is not part of the test suite yet; running it against the shell's bridge is on the Roadmap.

The docs are non-normative. Where a page here and the specification disagree, the specification wins and the page has a bug.

Recording a gap ​

A gap is anything kernl does that the specification does not say, or does not do that the specification says. Record it in three places:

  1. Next to the code, as a comment that names the clause and the upstream issue. This is one of the few comments the slop gate accepts, because a reader could not infer it.
  2. In DECISIONS.md, as a D-NNN entry with Context, Decision, Consequences and Reversal cost. If the gap is a kehto seam, the entry says what upstream change would close it.
  3. In Alpha status, under upstream gaps, so a reader deciding whether to depend on kernl sees it without reading the decisions log.

A gap closes when upstream lands and the local layer is deleted. The DECISIONS.md entry stays, with a Superseded by line.

Tie-breaking ​

Protocol conformance is second in SOUL.md's tie-breakers, below the user's safety and agency and above the applet developer's ability to build. A conformance requirement that would weaken the user's position is not implemented silently; it is raised upstream with the conflict stated, and DECISIONS.md records which way kernl went while the question is open.

MIT licensed. Protocol authority: NIP-5D (nostr-protocol/nips PR #2303) and the NAPs (napplet/naps).