diff --git a/scripts/validation/historiangw-131/README.md b/scripts/validation/historiangw-131/README.md
new file mode 100644
index 00000000..1e0b2622
--- /dev/null
+++ b/scripts/validation/historiangw-131/README.md
@@ -0,0 +1,56 @@
+# HistorianGateway consumer TLS migration — issue 131
+
+`consumer-1.0.0.patch` is a future consumer change, kept separate from the buildable
+application while the paired Client/Contracts 1.0.0 packages are being released.
+The application in this checkout remains pinned to published 0.4.0.
+
+The patch changes both central package pins to 1.0.0 and maps the new option as:
+
+```csharp
+AllowUntrustedServerCertificate = options.UseTls && options.AllowUntrustedServerCertificate,
+```
+
+The old inverse-mapping and obsolete h2c-history comments are removed. The existing
+h2c construction test now includes a stale opt-out as well as a stale CA path.
+Three new bounded local wire tests verify behavior through the real adapter and
+published client API, without reflection or replacing the transport handler:
+
+- TLS with normal defaults rejects a self-signed server before the metadata RPC.
+- Explicit opt-out permits that self-signed server shape and executes one RPC.
+- Plaintext with stale opt-out and CA settings executes one RPC, proving TLS-only
+ settings were not forwarded to the client's validating options.
+
+The local server uses an ephemeral loopback port and a fresh short-lived
+self-signed certificate. RPC completion is bounded to 15 seconds; the consumer
+call timeout is two seconds. No gateway, deployment, or global trust store is used.
+
+Before applying the patch, query the live Gitea NuGet version indexes for BOTH
+packages and require actual stable 1.0.0. Source `main` having the new API is not a
+package release. At initial inspection, both feed indexes listed exactly
+0.4.0, 0.3.0, 0.2.0, 0.1.0, and the new API was only in Unreleased at HG commit
+`e4321915ebc5e0704a68ecad21b85c1cc1c80d6b`.
+
+```bash
+git apply --check scripts/validation/historiangw-131/consumer-1.0.0.patch
+git apply scripts/validation/historiangw-131/consumer-1.0.0.patch
+# From the consumer checkout, using a fresh run/results directory:
+dotnet test tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests \
+ -c Release --logger trx --results-directory /absolute/fresh/results
+# Preserve dotnet test's exit; run the repository execution-count guard separately.
+MIN_EXECUTED=1 bash scripts/ci/assert-not-all-skipped.sh /absolute/fresh/results/*.trx
+```
+
+Published-package verification must use the real 1.0.0 packages, preserve all test
+and guard exits, run the full owning project, and complete the consumer solution
+build/review before issue 131 is closed. The patch is transport-only and can be
+applied independently of the OPC UA SDK 2 rollout.
+
+If release availability lags, validate only in an archived staging copy: materialize
+exact HG commit e432191 with `git archive`, pack both packages with the local-only
+version `1.0.0-validation.131`, set an isolated `NUGET_PACKAGES`, and map only those
+two package IDs to a task-local feed. Apply the future patch to a separate consumer
+archive, then replace ONLY its two package pins with the validation prerelease.
+Never pack/build the user's HG checkout, publish these validation packages, place
+them in the normal NuGet cache, or pass prerelease validation off as stable-release
+verification. Local validation and release availability results are recorded in
+`RESULTS.md` when the run completes.
diff --git a/scripts/validation/historiangw-131/RESULTS.md b/scripts/validation/historiangw-131/RESULTS.md
new file mode 100644
index 00000000..9dd18c51
--- /dev/null
+++ b/scripts/validation/historiangw-131/RESULTS.md
@@ -0,0 +1,13 @@
+# Validation status
+
+Preparation only: future patch passes `git apply --check` in the SDK 2 candidate
+checkout. Published Client/Contracts 1.0.0 package verification is pending.
+
+Initial primary feed query returned versions 0.4.0, 0.3.0, 0.2.0, 0.1.0 for both
+packages. HG e4321915ebc5e0704a68ecad21b85c1cc1c80d6b contains the new option under
+Unreleased; both source package version declarations still read 0.4.0. The cached
+published Client 0.4.0 exposes RequireCertificateValidation and does not expose the
+new property. Current consumer files remain on 0.4.0 and unchanged.
+
+No issue comment/close, package publication, or HG user-checkout modification has
+been performed. Test results will be added after actual execution.
diff --git a/scripts/validation/historiangw-131/consumer-1.0.0.patch b/scripts/validation/historiangw-131/consumer-1.0.0.patch
new file mode 100644
index 00000000..b22cd7a6
--- /dev/null
+++ b/scripts/validation/historiangw-131/consumer-1.0.0.patch
@@ -0,0 +1,210 @@
+diff --git a/Directory.Packages.props b/Directory.Packages.props
+--- a/Directory.Packages.props
++++ b/Directory.Packages.props
+@@ -242,7 +242,7 @@
+
+
+
+-
+-
++
++
+
+
+\ No newline at end of file
+diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway/HistorianGatewayClientAdapter.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway/HistorianGatewayClientAdapter.cs
+--- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway/HistorianGatewayClientAdapter.cs
++++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway/HistorianGatewayClientAdapter.cs
+@@ -57,23 +57,15 @@
+ $"ServerHistorian:Endpoint must be an absolute http(s) URI (e.g. https://host:5222); got '{options.Endpoint}'.");
+ }
+
+- // TLS-only options must stay at their defaults on a plaintext h2c connection: the client rejects
+- // each of them outright when UseTls=false (" is a TLS-only option and requires
+- // UseTls=true"). Forwarding them unconditionally made h2c UNREACHABLE — AllowUntrustedServer-
+- // Certificate defaults to false, so RequireCertificateValidation was always sent as true and
+- // every http:// deployment crashed at startup, even though the scheme is documented as the
+- // supported way to select h2c. There is no certificate to have a posture about here.
++ // Certificate settings apply only to TLS. The client rejects an explicit opt-out or a
++ // CA path on h2c, where there is no certificate to validate.
+ var clientOptions = new HistorianGatewayClientOptions
+ {
+ Endpoint = endpointUri,
+ ApiKey = options.ApiKey,
+ UseTls = options.UseTls,
+ CaCertificatePath = options.UseTls ? options.CaCertificatePath : null,
+- // INVERTED mapping (TLS only): ServerHistorianOptions.AllowUntrustedServerCertificate
+- // (opt-in to accept a self-signed cert) is the negation of the client's
+- // RequireCertificateValidation. Allowing an untrusted cert == not requiring validation; a
+- // pinned CaCertificatePath always verifies.
+- RequireCertificateValidation = options.UseTls && !options.AllowUntrustedServerCertificate,
++ AllowUntrustedServerCertificate = options.UseTls && options.AllowUntrustedServerCertificate,
+ DefaultCallTimeout = options.CallTimeout,
+ LoggerFactory = loggerFactory,
+ };
+diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/HistorianGatewayClientAdapterTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/HistorianGatewayClientAdapterTests.cs
+--- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/HistorianGatewayClientAdapterTests.cs
++++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/HistorianGatewayClientAdapterTests.cs
+@@ -27,23 +27,6 @@
+ /// A plaintext h2c gateway (an http:// endpoint with UseTls=false) must
+ /// construct, using nothing but documented defaults.
+ ///
+- ///
+- ///
+- /// Found by the LocalDb Phase 2 live gate, on the third consecutive crash-loop of the rig.
+- /// docs/Historian.md and CLAUDE.md both document http:// as a supported
+- /// transport ("scheme selects transport: https = TLS, http = h2c"), but it was in fact
+- /// unreachable: this factory forwarded the TLS-only options unconditionally, and
+- /// defaults to
+- /// , so it always sent RequireCertificateValidation=true —
+- /// which the client rejects outright when UseTls=false
+- /// ("RequireCertificateValidation is a TLS-only option and requires UseTls=true").
+- ///
+- ///
+- /// So every h2c deployment crashed at startup, and the only way to avoid it was to
+- /// set AllowUntrustedServerCertificate=true — asserting a certificate posture for a
+- /// connection that has no certificate at all.
+- ///
+- ///
+ [Fact]
+ public void Adapter_constructs_for_plaintext_h2c_endpoint()
+ {
+@@ -71,6 +54,7 @@
+ ApiKey = "histgw_x_y",
+ UseTls = false,
+ CaCertificatePath = "/etc/ssl/certs/leftover-from-a-tls-config.pem",
++ AllowUntrustedServerCertificate = true,
+ };
+
+ using var adapter = HistorianGatewayClientAdapter.Create(opts, NullLoggerFactory.Instance);
+diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/HistorianGatewayTlsPolicyWireTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/HistorianGatewayTlsPolicyWireTests.cs
+new file mode 100644
+--- /dev/null
++++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/HistorianGatewayTlsPolicyWireTests.cs
+@@ -0,0 +1,126 @@
++using System.Net;
++using System.Security.Cryptography;
++using System.Security.Cryptography.X509Certificates;
++using Grpc.Core;
++using Microsoft.AspNetCore.Builder;
++using Microsoft.AspNetCore.Hosting;
++using Microsoft.AspNetCore.Server.Kestrel.Core;
++using Microsoft.Extensions.DependencyInjection;
++using Microsoft.Extensions.Logging;
++using Microsoft.Extensions.Logging.Abstractions;
++using Shouldly;
++using Xunit;
++using ZB.MOM.WW.HistorianGateway.Client;
++using ZB.MOM.WW.HistorianGateway.Contracts.Grpc;
++using ZB.MOM.WW.OtOpcUa.Runtime.Historian;
++
++namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests;
++
++/// historiangw#131: verify the mapped TLS posture through an actual local gRPC connection.
++public sealed class HistorianGatewayTlsPolicyWireTests
++{
++ private static CancellationToken Ct => TestContext.Current.CancellationToken;
++
++ [Fact]
++ public async Task Default_tls_rejects_an_untrusted_server_before_the_rpc()
++ {
++ await using var server = await Server.StartAsync(tls: true);
++ using var adapter = HistorianGatewayClientAdapter.Create(server.Options(), NullLoggerFactory.Instance);
++
++ await Should.ThrowAsync(
++ () => adapter.TagExistsAsync("T", Ct).WaitAsync(TimeSpan.FromSeconds(15), Ct));
++ server.MetadataCalls.ShouldBe(0);
++ }
++
++ [Fact]
++ public async Task Explicit_tls_opt_out_reaches_the_same_self_signed_server_shape()
++ {
++ await using var server = await Server.StartAsync(tls: true);
++ var options = server.Options();
++ options.AllowUntrustedServerCertificate = true;
++ using var adapter = HistorianGatewayClientAdapter.Create(options, NullLoggerFactory.Instance);
++
++ (await adapter.TagExistsAsync("T", Ct).WaitAsync(TimeSpan.FromSeconds(15), Ct)).ShouldBeTrue();
++ server.MetadataCalls.ShouldBe(1);
++ }
++
++ [Fact]
++ public async Task Plaintext_ignores_stale_tls_opt_out_and_ca_settings_and_reaches_the_rpc()
++ {
++ await using var server = await Server.StartAsync(tls: false);
++ var options = server.Options();
++ options.AllowUntrustedServerCertificate = true;
++ options.CaCertificatePath = "/nonexistent/historiangw-131-stale-ca.pem";
++ using var adapter = HistorianGatewayClientAdapter.Create(options, NullLoggerFactory.Instance);
++
++ (await adapter.TagExistsAsync("T", Ct).WaitAsync(TimeSpan.FromSeconds(15), Ct)).ShouldBeTrue();
++ server.MetadataCalls.ShouldBe(1);
++ }
++
++ private sealed class TagsService : HistorianTags.HistorianTagsBase
++ {
++ public int Calls;
++ public override Task GetTagMetadata(GetTagMetadataRequest request, ServerCallContext context)
++ {
++ Interlocked.Increment(ref Calls);
++ return Task.FromResult(new GetTagMetadataReply
++ { Metadata = new HistorianTagMetadata { Name = request.Tag } });
++ }
++ }
++
++ private sealed class Server(WebApplication app, TagsService service, string endpoint,
++ RSA? key, X509Certificate2? certificate) : IAsyncDisposable
++ {
++ public int MetadataCalls => Volatile.Read(ref service.Calls);
++ public ServerHistorianOptions Options() => new()
++ {
++ Endpoint = endpoint, ApiKey = "histgw_131_test", UseTls = certificate is not null,
++ CallTimeout = TimeSpan.FromSeconds(2),
++ };
++
++ public static async Task StartAsync(bool tls)
++ {
++ RSA? key = null;
++ X509Certificate2? certificate = null;
++ if (tls)
++ {
++ key = RSA.Create(2048);
++ var request = new CertificateRequest("CN=localhost", key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
++ request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, true));
++ request.CertificateExtensions.Add(new X509KeyUsageExtension(
++ X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment, true));
++ var names = new SubjectAlternativeNameBuilder();
++ names.AddDnsName("localhost"); names.AddIpAddress(IPAddress.Loopback);
++ request.CertificateExtensions.Add(names.Build());
++ certificate = request.CreateSelfSigned(DateTimeOffset.UtcNow.AddMinutes(-5), DateTimeOffset.UtcNow.AddDays(1));
++ }
++ var service = new TagsService();
++ var builder = WebApplication.CreateBuilder();
++ builder.Logging.ClearProviders();
++ builder.WebHost.ConfigureKestrel(options => options.Listen(IPAddress.Loopback, 0, listen =>
++ {
++ listen.Protocols = HttpProtocols.Http2;
++ if (certificate is not null) listen.UseHttps(certificate);
++ }));
++ builder.Services.AddGrpc(); builder.Services.AddSingleton(service);
++ var app = builder.Build();
++ app.MapGrpcService();
++ try
++ {
++ await app.StartAsync(Ct);
++ return new Server(app, service, app.Urls.Single(), key, certificate);
++ }
++ catch
++ {
++ await app.DisposeAsync(); certificate?.Dispose(); key?.Dispose();
++ throw;
++ }
++ }
++
++ public async ValueTask DisposeAsync()
++ {
++ try { await app.StopAsync(Ct); }
++ finally { await app.DisposeAsync(); certificate?.Dispose(); key?.Dispose(); }
++ }
++ }
++}