Skip to content

feat(netlayer): Phase 6 — cleanup + docs (relay → location hint, netlayer guide) - #974

Draft
rekmarks wants to merge 9 commits into
rekm/netlayer-4from
rekm/netlayer-6
Draft

feat(netlayer): Phase 6 — cleanup + docs (relay → location hint, netlayer guide)#974
rekmarks wants to merge 9 commits into
rekm/netlayer-4from
rekm/netlayer-6

Conversation

@rekmarks

Copy link
Copy Markdown
Member

Final phase of the pluggable-netlayer effort (issue #968), stacked on #973 (rekm/netlayer-4). Phase 5 (@metamask/netlayer-websocket) is deferred by user decision — the effort goes Phase 4 → Phase 6 directly.

Phase 6 is cleanup + docs. It contains no functional changes beyond a terminology rename.

Rename: relay → location hint (kernel-generic surface)

The libp2p-flavored term "relay" is renamed to the netlayer-neutral "location hint" everywhere it is the kernel's own vocabulary:

  • store/methods/relay.tslocation-hints.ts; getRelayMethodsgetLocationHintMethods, get/setRelayEntriesget/setLocationHintEntries, getKnownRelayAddressesgetKnownLocationHintAddresses; persisted KV key knownRelaysknownLocationHints; the legacy string[] migration path is deleted (fresh-storage only, per the effort's break-freely decision).
  • RelayEntry/RelayEntryStructLocationHintEntry/LocationHintEntryStruct (the addr field name kept).
  • RemoteIdentity.addKnownRelaysaddKnownLocationHints; RemoteCommsOptions.maxUrlRelayHints/maxKnownRelaysmaxUrlLocationHints/maxKnownLocationHints (also in the kernel-control RPC struct and kernel-browser-runtime's comms-query-string).

config.knownRelays is deliberately NOT renamed — it is the netlayer-config seam with @metamask/netlayer-libp2p's Libp2pNetlayerConfig.knownRelays (the one config key the kernel injects by convention), and phase-6 explicitly excludes the libp2p package. Renaming only the kernel side would break the contract.

Docs

  • New docs/writing-a-netlayer.md: the Netlayer/ChannelProvider contracts, delivery semantics, incarnation handshake, identity requirements, error mapping, config/registration, testing guidance, a worked example, and an "iroh is the next (Node-only) netlayer" note.
  • New ## Networking glossary section (netlayer, location hint, neutral peer id, loopback netlayer, hub-and-spoke, incarnation handshake, ocap URL).
  • Stale-doc corrections: ken-protocol-assessment.md (FIFO/transport → netlayer per-connection ordering), usage.md + identity-backup-recovery.md (NetlayerSpecifier shape, neutral z… peer ids), platform-specific.md (packages/nodejs/packages/kernel-node-runtime/ + netlayer-injection note). The stale SES/@chainsafe/libp2p-yamux patch guidance moved off the now-libp2p-free ocap-kernel README onto @metamask/netlayer-libp2p.
  • Plan docs: master.md marks Phase 6 done with a landed-decisions block and an effort-complete summary; phase-5.md is re-reconciled against the final stack.

Coverage

Both touched packages meet/exceed their pre-phase baselines on two clean runs:

Package Stmts Branch Funcs Lines
ocap-kernel (baseline) 94.51 86.47 94.87 94.47
ocap-kernel (final) 94.52 86.48 95.00 94.49
kernel-browser-runtime 93.29 87.96 84.88 93.86 (unchanged)

Deleting the fully-covered migration path caused a ~0.02–0.07% arithmetic dip on ocap-kernel (no source regressed — uncovered-line count unchanged); it was closed above baseline with two behavior-asserting tests (bootstrap-hint sort order; remoteFor hint-registration failure).

Left for humans

  • @libp2p/webrtc endoify relocation (kernel-shims endoify-node.js) remains deferred and review-gated — a pre-lockdown import whose relocation touches ~7 packages with a silent-lockdown-failure risk. Not performed here.
  • Phase 5 (WebSocket netlayer) remains future work; its plan is reconciled and ready.

🤖 Generated with Claude Code

rekmarks and others added 6 commits July 10, 2026 20:13
…rface

Rename the libp2p-flavored term "relay" to the netlayer-neutral term "location
hint" across the kernel-generic surfaces where the concept is no longer
libp2p-specific: the persisted hint pool, its entry type, the store methods, the
kernel-level config options, and the RemoteIdentity accessor.

- `store/methods/relay.ts` -> `location-hints.ts`; `getRelayMethods` ->
  `getLocationHintMethods`, `getRelayEntries`/`setRelayEntries`/
  `getKnownRelayAddresses` -> their `LocationHint` equivalents; persisted KV key
  `knownRelays` -> `knownLocationHints`; drop the legacy `string[]` migration path.
- `RelayEntry`/`RelayEntryStruct` -> `LocationHintEntry`/`LocationHintEntryStruct`.
- `RemoteIdentity.addKnownRelays` -> `addKnownLocationHints`;
  `RemoteCommsOptions.maxUrlRelayHints`/`maxKnownRelays` ->
  `maxUrlLocationHints`/`maxKnownLocationHints` (also in the kernel-control RPC
  struct and the browser worker comms query string).

The libp2p netlayer's own config key `config.knownRelays` is deliberately left
as-is: it is the seam with `@metamask/netlayer-libp2p`'s `Libp2pNetlayerConfig`,
which keeps the "relay" name. Persisted state is not migrated (breaking, per the
netlayer plan's compatibility decision).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ibp2p references

- Add `docs/writing-a-netlayer.md`: the `Netlayer`/`ChannelProvider` contracts,
  delivery semantics, incarnation handshake, identity requirements, error
  mapping, config/registration, testing guidance, a worked example, and an iroh
  next-netlayer note (issue #968).
- Add a `## Networking` glossary section: netlayer, location hint, neutral peer
  id, loopback netlayer, hub-and-spoke, incarnation handshake, ocap URL.
- Generalize `ken-protocol-assessment.md`'s FIFO/transport claims from
  "TCP/libp2p" to the netlayer per-connection ordering contract.
- Update `usage.md` and `identity-backup-recovery.md` remote-comms examples to
  the `NetlayerSpecifier` shape and neutral (`z…`) peer ids.
- Fix stale `packages/nodejs/` paths in `platform-specific.md` to
  `packages/kernel-node-runtime/`, and note netlayer injection.
- Move the SES/libp2p patch guidance off the (now libp2p-free) ocap-kernel
  README onto `@metamask/netlayer-libp2p`; link the new guide from the netlayer
  package READMEs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…l stack

- master.md: add the Phase 6 "Landed decisions" block (the executed rename, the
  `config.knownRelays` seam kept, the docs shipped, coverage) and an
  "Effort complete" summary of what shipped across Phases 1–4+6 and what remains
  (Phase 5 deferred, the endoify relocation review item, the browser
  getListenAddresses gap, iroh as future work).
- phase-5.md: update the deferral banner to record that Phase 6 has landed and
  reconcile the plan against it — the relay→location-hint rename touched the
  kernel surface but not the `config.knownRelays` netlayer-config seam, so the
  plan's use of that key for `wss://` hub URLs still holds; point at the new
  writing-a-netlayer guide and glossary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Document the README/test-helper touches in the packages Phase 6 modified
incidentally (the three netlayer package READMEs and the libp2p e2e test
helper), so the changelog check passes for every changed published package.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rekmarks rekmarks closed this Jul 11, 2026
@rekmarks rekmarks reopened this Jul 11, 2026
@github-actions

github-actions Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 72.31%
⬆️ +0.95%
9058 / 12526
🔵 Statements 72.13%
⬆️ +0.94%
9207 / 12763
🔵 Functions 73.44%
⬆️ +0.87%
2193 / 2986
🔵 Branches 65.76%
⬆️ +0.90%
3655 / 5558
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/kernel-browser-runtime/src/utils/comms-query-string.ts 97.56%
⬇️ -2.44%
91.66%
⬇️ -8.34%
100%
🟰 ±0%
97.56%
⬇️ -2.44%
99-101
packages/ocap-kernel/src/remotes/types.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/remotes/kernel/OcapURLManager.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/remotes/kernel/remote-comms.ts 100%
⬆️ +0.73%
100%
⬆️ +3.04%
100%
🟰 ±0%
100%
⬆️ +0.75%
packages/ocap-kernel/src/rpc/kernel-control/init-remote-comms.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/store/index.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/store/types.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
packages/ocap-kernel/src/store/methods/location-hints.ts 100% 83.33% 100% 100%
Generated in workflow #4524 for commit be2a958 by the Vitest Coverage Report Action

rekmarks and others added 3 commits July 10, 2026 20:58
Brings in 961d968: the reworded endoify follow-up note in master.md and the
new phase-6.md §1a 'Follow-ups carried from Phase 4' section.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rule, libp2pComms)

- Add a packaging section to the writing-a-netlayer guide documenting the
  load-bearing tsconfig.packages.json subpath→src mapping rule for
  netlayer-libp2p (§1a.4): a missing mapping makes vitest resolve to dist and
  initialize a second post-lockdown @libp2p/webrtc, crashing SES.
- Record the libp2pComms test-helper retirement (§1a.3) as tracked future work
  in master.md's effort-complete summary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add the user-requested draft plan for @metamask/netlayer-iroh (proposed to
supersede the deferred WebSocket phase as the second real ChannelProvider, plus
a provider-conformance test kit). Reconcile it with landed Phase 6: add the
kernel's config.knownRelays convention key to its config sketch, link the
writing-a-netlayer guide + glossary and the guide's packaging/tsconfig section.

Cross-link the draft (marked DRAFT/unscheduled) from master.md's effort-complete
iroh bullet and the guide's iroh note, and add one banner sentence to phase-5.md
noting the draft exists (Phase 5 remains an independent future option).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@FUDCo FUDCo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Commentary on the writing-a-netlayer document.

Comment on lines +61 to +63
- **`peerId`** — the [neutral peer id](./glossary.md#neutral-peer-id): the base58btc-multibase
encoding of the raw Ed25519 public key derived from the `keySeed` the netlayer was
constructed with. It **must** equal `deriveNeutralPeerId(fromHex(keySeed))`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A peer ID is generally employed in the context of the identity that one is trying to contact. However, in this case this peerId property is the peer ID of the local kernel, the identity others should use if they wish to contact "me". This should be made clear.

reached. These become the location hints the kernel embeds in the [ocap
URLs](./glossary.md#ocap-url) it issues. Return `[]` if the node cannot be dialed
(e.g. a browser client).
- **`stop()`** — tear everything down; after `stop`, sends reject.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This needs better explanation. Does it mean "terminate all currently live communications activity and throw away all the runtime state for this execution of the kernel" or does it mean "make this peer go away forever"? I.e., does it make what would happen if the process called exit() happen but without actually exiting, or is it like calling closeConnection() on every open connection or is it something more drastic and permanent? Also, what does "after stop, sends reject" mean? Sends reject to whom in response to what?

};

export type ChannelProvider = {
readonly peerId: string;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Once again, I think this means "my peerId", in contrast to the NetworkChannel interface where it means "their peerId". Possibly it might make sense to revise the names to be clear about this distinction.

});
```

The engine owns handshake-before-register, the `reuseOrReturnChannel` race, the single

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Here (and probably elsewhere) it's somewhat unclear what entity "the engine" designates. I think it means the generic parts of the netlayer implementation as instantiated by the kernel, but I'm not 100% sure.

Comment on lines +157 to +158
- **`handleMessage(from, message)`** — deliver an inbound message to the kernel. A non-null
return value is a piggyback reply to send back on the same connection.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The relationship between handleMessage() here and read() in the NetworkChannel interface is unclear.

size validation, stale-peer cleanup, and intentional-close bookkeeping. Share one
`AbortController` between the provider and the engine: `Netlayer.stop()` aborts it.

## 4. Hooks (`NetlayerHooks`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There probably should be an introductory sentence or two explaining what this is and what its role in the overall picture is. Actually, the Overview (section 1 above) probably should have a section that just summarizes what the various component abstractions are and their relationships to each other.


## 5. Delivery-semantics contract

State the guarantee precisely, because the kernel depends on exactly this and no more:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is confusing. Why do I need to state the guarantee precisely? I think this document needs to state that, and I think it was the intent of this sentence to declare that that is what this section was doing, but the phrasing is unclear. This feels like this was maybe the prompt to Claude telling it to produce this section, but out of context it's weird.

Comment on lines +167 to +169
- **Best-effort, ordered per live connection.** Messages written to one live connection are
delivered in order or not at all. You **MUST NOT** reorder messages within a single
connection.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Implied but not stated, but worth stating, is that there is no intent to enforce any kind of ordering between concurrent connections.

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.

2 participants