diff --git a/docs/DataChannels.md b/docs/DataChannels.md
index 6fd97c8b5d..2c0a321ae5 100644
--- a/docs/DataChannels.md
+++ b/docs/DataChannels.md
@@ -56,14 +56,25 @@ sequence-checks every chunk before the engine sees it. Core itself carries no da
vocabulary — `ISecureChannelMessageExtension` and `ISecureChannelMessageHost` name only "a
MessageType that is neither a Service call nor part of establishing the SecureChannel".
+Both are `internal`, reached through the `InternalsVisibleTo` that Core already grants its
+sibling first-party assemblies (`Opc.Ua.Client`, `Opc.Ua.Bindings.Quic`,
+`Opc.Ua.Bindings.Https`). The seam exists to keep the engine out of Core, not to invite
+other implementers — there is exactly one, and the `opc.quic` binding does not use any of
+it, because a QUIC data channel rides its own stream and never becomes a UASC chunk.
+Publishing it would commit Core to an abstraction with one implementer for ever.
+
Two things stay in Core because they are the SecureChannel's own concerns rather than the
feature's: `SequenceNumberBudget`, which tracks the sequence space every MessageType draws
on, and `UaSCSecureChannelRegistry`, which maps a SecureChannel identifier to the channel
-that owns it. Because the budget is Core's, the channel claims the SequenceNumber itself
-while it secures the chunk and refuses the send with `Bad_SecureChannelTokenUnknown` when
-the space under the current token is exhausted — an extension stalls rather than reuse a
-number, and never has to reason about the serialization to do so. The `opc.quic` transport
-remains its own package, `OPCFoundation.NetStandard.Opc.Ua.Bindings.Quic`.
+that owns it. The budget is internal for the same reason as the seam; the registry is
+public because an application writing its own `IServerDataChannelTransport` for inline
+framing needs it to resolve the channel behind a request, which
+`samples/ConsoleDataChannelStreaming` demonstrates. Because the budget is Core's, the
+channel claims the SequenceNumber itself while it secures the chunk and refuses the send
+with `Bad_SecureChannelTokenUnknown` when the space under the current token is exhausted —
+an extension stalls rather than reuse a number, and never has to reason about the
+serialization to do so. The `opc.quic` transport remains its own package,
+`OPCFoundation.NetStandard.Opc.Ua.Bindings.Quic`.
## Server side
diff --git a/src/Opc.Ua.Core.Channels/DataChannels/DataChannelExtension.cs b/src/Opc.Ua.Core.Channels/DataChannels/DataChannelExtension.cs
index f8da82d827..00b39b014d 100644
--- a/src/Opc.Ua.Core.Channels/DataChannels/DataChannelExtension.cs
+++ b/src/Opc.Ua.Core.Channels/DataChannels/DataChannelExtension.cs
@@ -42,7 +42,7 @@ namespace Opc.Ua.Bindings
/// This owns the STR MessageType on the channel and is the only thing that
/// knows the frame format; the channel itself sees an opaque body.
///
- public sealed class DataChannelExtension : ISecureChannelMessageExtension, IDataChannelTransport
+ internal sealed class DataChannelExtension : ISecureChannelMessageExtension, IDataChannelTransport
{
///
/// Attaches data channels to a SecureChannel.
diff --git a/src/Opc.Ua.Core.Channels/UaSCDataChannelExtensions.cs b/src/Opc.Ua.Core.Channels/UaSCDataChannelExtensions.cs
index 1a39843ed7..f648992301 100644
--- a/src/Opc.Ua.Core.Channels/UaSCDataChannelExtensions.cs
+++ b/src/Opc.Ua.Core.Channels/UaSCDataChannelExtensions.cs
@@ -111,10 +111,16 @@ namespace Opc.Ua.Bindings
/// Returns the extension that owns the STR MessageType on a
/// SecureChannel, if one is registered.
///
+ ///
+ /// The extension is an implementation detail of the inline framing:
+ /// a consumer reaches the channels through
+ /// , which returns the engine rather
+ /// than the adapter that drives it.
+ ///
/// The SecureChannel.
/// The extension.
/// is null.
- public static bool TryGetDataChannelExtension(
+ internal static bool TryGetDataChannelExtension(
this UaSCUaBinaryChannel channel,
out DataChannelExtension? extension)
{
diff --git a/src/Opc.Ua.Core/Opc.Ua.Core.csproj b/src/Opc.Ua.Core/Opc.Ua.Core.csproj
index 20b2c981e0..449293d2e3 100644
--- a/src/Opc.Ua.Core/Opc.Ua.Core.csproj
+++ b/src/Opc.Ua.Core/Opc.Ua.Core.csproj
@@ -23,6 +23,7 @@
+
diff --git a/src/Opc.Ua.Core/Stack/Tcp/ISecureChannelMessageExtension.cs b/src/Opc.Ua.Core/Stack/Tcp/ISecureChannelMessageExtension.cs
index f30316b422..05c972907a 100644
--- a/src/Opc.Ua.Core/Stack/Tcp/ISecureChannelMessageExtension.cs
+++ b/src/Opc.Ua.Core/Stack/Tcp/ISecureChannelMessageExtension.cs
@@ -43,7 +43,7 @@ namespace Opc.Ua.Bindings
/// from the channel's single SequenceNumber space. This is the surface that
/// makes that possible without publishing the channel's internals.
///
- public interface ISecureChannelMessageHost
+ internal interface ISecureChannelMessageHost
{
///
/// The largest chunk the peer accepts.
@@ -114,7 +114,7 @@ namespace Opc.Ua.Bindings
/// faults, which is what OPC 10000-6 §6.7.2.2 requires of a receiver that
/// does not implement it.
///
- public interface ISecureChannelMessageExtension
+ internal interface ISecureChannelMessageExtension
{
///
/// The MessageType this extension owns, without the chunk type.
diff --git a/src/Opc.Ua.Core/Stack/Tcp/SequenceNumberBudget.cs b/src/Opc.Ua.Core/Stack/Tcp/SequenceNumberBudget.cs
index 249220b916..e2d1703716 100644
--- a/src/Opc.Ua.Core/Stack/Tcp/SequenceNumberBudget.cs
+++ b/src/Opc.Ua.Core/Stack/Tcp/SequenceNumberBudget.cs
@@ -64,7 +64,7 @@ namespace Opc.Ua.Bindings
/// than emitting a chunk that would reuse a value.
///
///
- public sealed class SequenceNumberBudget
+ internal sealed class SequenceNumberBudget
{
///
/// Creates a budget.
diff --git a/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.MessageExtensions.cs b/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.MessageExtensions.cs
index e6d686435b..1711120965 100644
--- a/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.MessageExtensions.cs
+++ b/src/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.MessageExtensions.cs
@@ -60,7 +60,7 @@ namespace Opc.Ua.Bindings
/// under the current SecurityToken. Every MessageType the channel
/// carries draws on the same space.
///
- public SequenceNumberBudget SequenceBudget
+ internal SequenceNumberBudget SequenceBudget
{
get
{
@@ -89,7 +89,7 @@ namespace Opc.Ua.Bindings
/// The registered extension, which is
/// unless another was registered first.
/// is null.
- public ISecureChannelMessageExtension RegisterMessageExtension(
+ internal ISecureChannelMessageExtension RegisterMessageExtension(
ISecureChannelMessageExtension extension)
{
if (extension == null)
@@ -105,7 +105,7 @@ namespace Opc.Ua.Bindings
///
/// The MessageType, without the chunk type.
/// The extension.
- public bool TryGetMessageExtension(
+ internal bool TryGetMessageExtension(
uint messageType,
out ISecureChannelMessageExtension? extension)
{