Skip to content

Commit b21c9ee

Browse files
committed
Fix comparison callers and add portable SIMD validation
1 parent 959a4c8 commit b21c9ee

33 files changed

Lines changed: 3527 additions & 109 deletions

‎.github/workflows/ci.yml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ jobs:
5353
- name: Verify source-owned Roslyn rules
5454
run: dotnet test --project tests/KeyLoad.Analyzers.Tests --no-build --no-restore --configuration Release
5555
- run: dotnet test --project tests/KeyLoad.UnitTests --no-build --no-restore --configuration Release
56+
- name: Qualify the full unit suite with hardware intrinsics disabled
57+
run: dotnet test --project tests/KeyLoad.UnitTests --no-build --no-restore --configuration Release --results-directory TestResults/unit-scalar
58+
env:
59+
DOTNET_EnableHWIntrinsic: 0
5660
- name: Qualify real process recovery after a successful build
5761
if: ${{ !cancelled() && steps.build.outcome == 'success' }}
5862
run: dotnet test --project tests/KeyLoad.RecoveryTests --no-build --no-restore --configuration Release

‎AGENTS.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ ManagedCode packages are our projects. Fix dependency defects in their owning si
1717
- When the user requests committing all current changes, commit the full requested working-tree scope on the currently checked-out branch; do not silently omit existing changes or move them to another branch.
1818

1919
## System-critical SMID and operation efficiency
20-
- Treat the owner's SMID work as a first-priority product workstream and keep it visible in implementation planning and status. The term is not defined in the current repository or v0.3 architecture documents; do not guess its expansion or begin SMID-specific implementation until its canonical slice, REQ/AC criteria and required ADRs are mapped with the owner.
20+
- Treat the owner's SIMD work (earlier written as SMID) as a first-priority product workstream and keep it visible in implementation planning and status. On 2026-10-02 the owner confirmed SIMD means vectorized CPU operations and directed .NET intrinsics first, with Rust considered only after profiling. Map its canonical slices, REQ/AC criteria, scalar correctness/portability contract and required ADRs before implementation; never claim acceleration without comparable GitHub measurements.
2121
- Orleans provides request isolation, cluster routing and activation movement. Keep the one-grain-per-request boundary and RF3 topology; treat Orleans Streams as a first-class architecture workstream to specify and qualify alongside persisted KeyLoad EventStreams. Keep their distinct delivery/restart contracts explicit, and define bounded resource, concurrency, backpressure, recovery and performance behavior for every operation.
2222
- Optimize each operation only against its correctness and fault contracts, using representative multi-node GitHub qualification to measure latency, throughput, allocations, memory, contention and backlog where applicable. Architecture choices or local builds alone do not prove maximum scalability or performance.
23+
- Use ZoneTree's native storage APIs correctly and Orleans for bounded parallel execution of independent operation work. Preserve node-local storage ownership, the ordered atomic commit/apply gate, scoped read cuts, cancellation and backpressure; qualify the resulting performance in real multi-node GitHub runs (owner direction 2026-10-02).
2324

2425
## MCAF repository workflow
2526

‎README.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ This is an early implementation of the clustered kernel. The default server topo
1414

1515
Implemented surfaces include document CRUD and field patches, partition-scoped unique/composite equality indexes, command deduplication, stream expected-revision append/read, retained topics, per-source durable subscriptions with bounded delivery windows and contiguous checkpoints, scheduled work queues with fenced leases and retry/DLQ, atomic inbox completion, a committed projection outbox with generation pins, protected resumable document changes and scalar live queries, bounded property-graph traversal, ordered samples, exact vector search, BM25 and weighted reciprocal-rank fusion, a bounded read-only Q1 SQL dialect, API keys, field omission and field-use policies, verified backups, native Raft snapshots and empty-replica catch-up, offline journal compaction, a .NET SDK and CLI.
1616

17-
The additive [TimeSeries reads](docs/Features/TimeSeries.md) provide latest samples, complete half-open raw aggregates and dense UTC windows through typed SDK, HTTP and MCP operations using published `ManagedCode.TimeSeries` 10.0.0. They preserve the existing inclusive sample range API and persisted authorization. The first complete new-source CI exposed test fixture/catalog/cancellation expectations; their [source corrections](docs/implementation/qualification-source-r9.json) require their own delivered-SHA CI.
17+
The additive [TimeSeries reads](docs/Features/TimeSeries.md) provide latest samples, complete half-open raw aggregates and dense UTC windows through typed SDK, HTTP and MCP operations using published `ManagedCode.TimeSeries` 10.0.0. They preserve the existing inclusive sample range API and persisted authorization. Their fixture/catalog/cancellation corrections are exercised in [exact c486 CI](docs/implementation/runtime-qualification-37060131271.json): 871/871 unit cases on each OS and 46/46 genuine RF3 SDK/MCP cases pass. Retention, rollups, SQL integration and resource qualification remain open.
18+
19+
That complete workflow still fails: Windows recovery is 116/136 and native comparison completion is 2/4; measured profiles were skipped. [The performance diagnosis](docs/implementation/performance-diagnosis-37060131271.json) records missing RF3/Rabbit caller bindings and PostgreSQL stream readback, plus unqualified 48-sample TimeSeries observations. These do not establish a performance winner. The next source stage repairs those callers and adds portable .NET SIMD finite-value validation with unchanged scoring, plus a full unit-suite invocation with intrinsics disabled. Its own delivered-SHA tests and measured benefit are pending; Rust requires profiling evidence first.
1820

1921
The [104-task implementation tracker](docs/implementation/status.json) records the remaining work. Automatic canonical journal maintenance, large and interrupted snapshot transfer qualification, shard movement, distributed multi-shard query planning, managed HNSW, subscription coverage discovery across partitions and rebalance, automatic retention and generation cleanup, schema migrations, external backup stores and full release qualification remain under development. The current server uses one replicated physical shard which contains many independent atomic partitions.
2022

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
using System.Collections.Immutable;
2+
using System.Globalization;
3+
using System.Net.Http.Headers;
4+
using System.Text;
5+
using Microsoft.Extensions.Configuration;
6+
7+
namespace KeyLoad.ComparisonHost.Features.BenchmarkComparisons;
8+
9+
/// <summary>Validates endpoints and credentials required by the comparison host callers.</summary>
10+
internal static class ComparisonEndpointBindings
11+
{
12+
private const string HttpScheme = "http";
13+
private const string HttpsScheme = "https";
14+
private const string UriRootPath = "/";
15+
private const int PrimaryEndpointIndex = 0;
16+
private const string FirstEndpointIndex = "0";
17+
private const string SecondEndpointIndex = "1";
18+
private const string ThirdEndpointIndex = "2";
19+
20+
internal static ImmutableArray<Uri> ReadKeyLoadEndpoints(IConfiguration configuration, Uri primary)
21+
{
22+
var endpoints = ImmutableArray.CreateBuilder<Uri>(ComparisonHostConstants.KeyLoadEndpointCount);
23+
for (var index = 0; index < ComparisonHostConstants.KeyLoadEndpointCount; index++)
24+
{
25+
var key = ComparisonHostConstants.KeyLoadEndpoints + ":" + index.ToString(CultureInfo.InvariantCulture);
26+
if (!TryParseHttpOrigin(ComparisonHostSettings.RequiredValue(configuration, key), out var endpoint))
27+
{
28+
throw InvalidKeyLoadEndpoints();
29+
}
30+
31+
endpoints.Add(endpoint);
32+
}
33+
34+
var children = configuration.GetSection(ComparisonHostConstants.KeyLoadEndpoints).GetChildren().ToArray();
35+
if (children.Length != ComparisonHostConstants.KeyLoadEndpointCount ||
36+
children.Any(child => child.Key is not (FirstEndpointIndex or SecondEndpointIndex or ThirdEndpointIndex)))
37+
{
38+
throw InvalidKeyLoadEndpoints();
39+
}
40+
41+
var result = endpoints.MoveToImmutable();
42+
var seenOrigins = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
43+
foreach (var endpoint in result)
44+
{
45+
if (!seenOrigins.Add(endpoint.GetLeftPart(UriPartial.Authority)))
46+
{
47+
throw InvalidKeyLoadEndpoints();
48+
}
49+
}
50+
51+
if (!IsHttpOrigin(primary) || !SameOrigin(primary, result[PrimaryEndpointIndex]))
52+
{
53+
throw InvalidKeyLoadEndpoints();
54+
}
55+
56+
return result;
57+
}
58+
59+
internal static Uri ReadRabbitManagementEndpoint(IConfiguration configuration)
60+
{
61+
var value = ComparisonHostSettings.RequiredValue(configuration,
62+
ComparisonHostConstants.RabbitManagementEndpoint);
63+
if (!TryParseHttpOrigin(value, out var endpoint))
64+
{
65+
throw new InvalidOperationException(ComparisonHostConstants.RabbitManagementEndpointInvalidCode);
66+
}
67+
68+
return endpoint;
69+
}
70+
71+
internal static void ValidateRabbitCredentials(string user, string password)
72+
{
73+
if (string.IsNullOrWhiteSpace(user) || string.IsNullOrWhiteSpace(password) ||
74+
user.Contains(ComparisonHostConstants.UserPasswordSeparator, StringComparison.Ordinal) ||
75+
ContainsLineBreak(user) || ContainsLineBreak(password))
76+
{
77+
throw new InvalidOperationException(ComparisonHostConstants.RabbitManagementCredentialsInvalidCode);
78+
}
79+
}
80+
81+
internal static AuthenticationHeaderValue CreateRabbitAuthorization(string user, string password)
82+
{
83+
var credential = user + ComparisonHostConstants.UserPasswordSeparator + password;
84+
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(credential));
85+
return new AuthenticationHeaderValue(ComparisonHostConstants.BasicAuthenticationScheme, token);
86+
}
87+
88+
private static bool TryParseHttpOrigin(string value, out Uri endpoint)
89+
{
90+
if (Uri.TryCreate(value, UriKind.Absolute, out var parsed) && IsHttpOrigin(parsed))
91+
{
92+
endpoint = parsed;
93+
return true;
94+
}
95+
96+
endpoint = null!;
97+
return false;
98+
}
99+
100+
private static bool IsHttpOrigin(Uri endpoint)
101+
=> (string.Equals(endpoint.Scheme, HttpScheme, StringComparison.OrdinalIgnoreCase) ||
102+
string.Equals(endpoint.Scheme, HttpsScheme, StringComparison.OrdinalIgnoreCase)) &&
103+
!string.IsNullOrWhiteSpace(endpoint.Host) && endpoint.UserInfo.Length == 0 &&
104+
endpoint.Query.Length == 0 && endpoint.Fragment.Length == 0 &&
105+
string.Equals(endpoint.AbsolutePath, UriRootPath, StringComparison.Ordinal);
106+
107+
private static bool SameOrigin(Uri left, Uri right)
108+
=> string.Equals(left.GetLeftPart(UriPartial.Authority), right.GetLeftPart(UriPartial.Authority),
109+
StringComparison.OrdinalIgnoreCase);
110+
111+
private static bool ContainsLineBreak(string value)
112+
=> value.Contains('\r', StringComparison.Ordinal) || value.Contains('\n', StringComparison.Ordinal);
113+
114+
private static InvalidOperationException InvalidKeyLoadEndpoints()
115+
=> new(ComparisonHostConstants.KeyLoadEndpointInvalidCode);
116+
}

‎benchmarks/KeyLoad.ComparisonHost/Features/BenchmarkComparisons/ComparisonHostConstants.cs‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ namespace KeyLoad.ComparisonHost.Features.BenchmarkComparisons;
33
internal static class ComparisonHostConstants
44
{
55
internal const string KeyLoadEndpoint = "Benchmarks:KeyLoadEndpoint";
6+
internal const string KeyLoadEndpoints = "Benchmarks:KeyLoadEndpoints";
7+
internal const string KeyLoadEndpointInvalidCode = "KeyLoadComparisonEndpointsInvalid";
68
internal const string Profile = "Benchmarks:Profile";
79
internal const string TimeSeriesProfile = "timeseries";
810
internal const string TimescaleConnection = "ConnectionStrings:benchmark-timescale";
@@ -14,6 +16,11 @@ internal static class ComparisonHostConstants
1416
internal const string AdminKey = "Benchmarks:AdminKey";
1517
internal const string PostgresConnection = "ConnectionStrings:benchmark-postgres";
1618
internal const string RabbitConnection = "ConnectionStrings:benchmark-rabbit";
19+
internal const string RabbitManagementEndpoint = "Benchmarks:RabbitManagementEndpoint";
20+
internal const string RabbitUser = "Benchmarks:RabbitUser";
21+
internal const string RabbitPassword = "Benchmarks:RabbitPassword";
22+
internal const string RabbitManagementEndpointInvalidCode = "RabbitManagementEndpointInvalid";
23+
internal const string RabbitManagementCredentialsInvalidCode = "RabbitManagementCredentialsInvalid";
1724
internal const string RedisConnection = "ConnectionStrings:benchmark-redis";
1825
internal const string PostgresImage = "Benchmarks:Images:Postgres";
1926
internal const string QdrantImage = "Benchmarks:Images:Qdrant";
@@ -38,6 +45,7 @@ internal static class ComparisonHostConstants
3845
internal const int FailedExitCode = 1;
3946
internal const int LifetimeHours = 2;
4047
internal const int TargetCount = 6;
41-
internal const int HttpClientCount = 3;
48+
internal const int KeyLoadEndpointCount = 3;
49+
internal const int HttpClientCount = 6;
4250
internal static readonly TimeSpan InfiniteTimeout = Timeout.InfiniteTimeSpan;
4351
}

‎benchmarks/KeyLoad.ComparisonHost/Features/BenchmarkComparisons/ComparisonHostSettings.cs‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Immutable;
12
using KeyLoad.Comparisons;
23
using Microsoft.Extensions.Configuration;
34

@@ -7,13 +8,17 @@ namespace KeyLoad.ComparisonHost.Features.BenchmarkComparisons;
78
/// <param name="Options">Validated workload options.</param>
89
/// <param name="RunId">Unique identifier used to isolate target data.</param>
910
/// <param name="KeyLoadEndpoint">KeyLoad endpoint.</param>
11+
/// <param name="KeyLoadEndpoints">Immutable KeyLoad RF3 peer endpoints, including the primary endpoint.</param>
1012
/// <param name="QdrantEndpoint">Qdrant endpoint.</param>
1113
/// <param name="QdrantApiKey">Qdrant API key.</param>
1214
/// <param name="Neo4jEndpoint">Neo4j endpoint.</param>
1315
/// <param name="Neo4jPassword">Neo4j password.</param>
1416
/// <param name="AdminKey">KeyLoad administrator key.</param>
1517
/// <param name="PostgresConnection">PostgreSQL connection string.</param>
1618
/// <param name="RabbitConnection">RabbitMQ connection string.</param>
19+
/// <param name="RabbitManagementEndpoint">RabbitMQ management API endpoint.</param>
20+
/// <param name="RabbitUser">RabbitMQ management API user.</param>
21+
/// <param name="RabbitPassword">RabbitMQ management API password.</param>
1722
/// <param name="RedisConnection">Redis connection string.</param>
1823
/// <param name="PostgresImage">PostgreSQL image label.</param>
1924
/// <param name="QdrantImage">Qdrant image label.</param>
@@ -27,13 +32,17 @@ internal sealed record ComparisonHostSettings(
2732
ComparisonOptions Options,
2833
string RunId,
2934
Uri KeyLoadEndpoint,
35+
ImmutableArray<Uri> KeyLoadEndpoints,
3036
Uri QdrantEndpoint,
3137
string QdrantApiKey,
3238
Uri Neo4jEndpoint,
3339
string Neo4jPassword,
3440
string AdminKey,
3541
string PostgresConnection,
3642
string RabbitConnection,
43+
Uri RabbitManagementEndpoint,
44+
string RabbitUser,
45+
string RabbitPassword,
3746
string RedisConnection,
3847
string PostgresImage,
3948
string QdrantImage,
@@ -53,6 +62,7 @@ internal static ComparisonHostSettings Read(IConfiguration configuration)
5362
var options = ComparisonOptions.Read(configuration);
5463
var keyLoadEndpoint = ReadEndpoint(configuration, ComparisonHostConstants.KeyLoadEndpoint);
5564
var qdrantEndpoint = ReadEndpoint(configuration, ComparisonHostConstants.QdrantEndpoint);
65+
var keyLoadEndpoints = ComparisonEndpointBindings.ReadKeyLoadEndpoints(configuration, keyLoadEndpoint);
5666
var qdrantApiKey = Required(configuration, ComparisonHostConstants.QdrantApiKey);
5767
var neo4jEndpoint = ReadEndpoint(configuration, ComparisonHostConstants.Neo4jEndpoint);
5868
var neo4jPassword = Required(configuration, ComparisonHostConstants.Neo4jPassword);
@@ -61,6 +71,10 @@ internal static ComparisonHostSettings Read(IConfiguration configuration)
6171
var postgresImage = Required(configuration, ComparisonHostConstants.PostgresImage);
6272
var qdrantImage = Required(configuration, ComparisonHostConstants.QdrantImage);
6373
var rabbitConnection = Required(configuration, ComparisonHostConstants.RabbitConnection);
74+
var rabbitManagementEndpoint = ComparisonEndpointBindings.ReadRabbitManagementEndpoint(configuration);
75+
var rabbitUser = Required(configuration, ComparisonHostConstants.RabbitUser);
76+
var rabbitPassword = Required(configuration, ComparisonHostConstants.RabbitPassword);
77+
ComparisonEndpointBindings.ValidateRabbitCredentials(rabbitUser, rabbitPassword);
6478
var rabbitImage = Required(configuration, ComparisonHostConstants.RabbitImage);
6579
var redisConnection = Required(configuration, ComparisonHostConstants.RedisConnection);
6680
var redisImage = Required(configuration, ComparisonHostConstants.RedisImage);
@@ -69,14 +83,17 @@ internal static ComparisonHostSettings Read(IConfiguration configuration)
6983
var output = Path.GetFullPath(Required(configuration, ComparisonHostConstants.Output));
7084
var sourceRevision = configuration[ComparisonHostConstants.SourceRevision];
7185
return new(options, Guid.NewGuid().ToString(ComparisonHostConstants.GuidFormat), keyLoadEndpoint,
72-
qdrantEndpoint, qdrantApiKey, neo4jEndpoint, neo4jPassword, adminKey, postgresConnection,
73-
rabbitConnection, redisConnection, postgresImage, qdrantImage, rabbitImage, redisImage, neo4jImage,
86+
keyLoadEndpoints, qdrantEndpoint, qdrantApiKey, neo4jEndpoint, neo4jPassword, adminKey, postgresConnection,
87+
rabbitConnection, rabbitManagementEndpoint, rabbitUser, rabbitPassword, redisConnection,
88+
postgresImage, qdrantImage, rabbitImage, redisImage, neo4jImage,
7489
output, storage, sourceRevision);
7590
}
7691

7792
private static Uri ReadEndpoint(IConfiguration configuration, string key)
7893
=> new(Required(configuration, key), UriKind.Absolute);
7994

80-
private static string Required(IConfiguration configuration, string key)
95+
internal static string RequiredValue(IConfiguration configuration, string key)
8196
=> configuration[key] ?? throw new InvalidOperationException(ComparisonHostConstants.MissingSettingPrefix + key);
97+
98+
private static string Required(IConfiguration configuration, string key) => RequiredValue(configuration, key);
8299
}

0 commit comments

Comments
 (0)