Skip to content

Commit aed338c

Browse files
committed
Fix admin document browsing and canonical event expectations
1 parent 1bee260 commit aed338c

10 files changed

Lines changed: 52 additions & 16 deletions

File tree

‎docs/ADR/ADR-039-official-mcp-agent-api.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,10 @@ limits. Native BlobResourceContents.FromBytes receives raw bytes; official clien
185185
use DecodedData, avoiding double base64. Native resources/read has no IsError;
186186
unresolved URIs use safe protocol InvalidParams for the current revision. No
187187
unfinished blob tool or resource may be advertised. The current source catalog
188-
contains 47 operations: the base 37 below plus ten implemented-source BlobStorage
189-
tools whose names/routes/contracts are frozen by ADR-038. All runtime and delivery
190-
gates remain pending; a catalog count does not qualify blob semantics.
188+
contains 50 operations: the base 37 below, ten implemented-source BlobStorage
189+
tools whose names/routes/contracts are frozen by ADR-038, and three additive
190+
read-only [AdminDashboard](ADR-051-admin-dashboard.md) tools. All runtime and
191+
delivery gates remain pending; a catalog count does not qualify blob semantics.
191192

192193
```mermaid
193194
flowchart LR

‎docs/Features/AdminDashboard.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ Manual exception: subjective visual polish is inspected via desktop/mobile scree
8080

8181
REQ/AC-AD-001..007 map to ADR-051 and tasks AD-C (shared integration), AD-B (backend), AD-U (UI), AD-T (tests) and AD-J (lead review/delivery). The requirement table and criterion-to-test matrix identify the automated owning suites. The subjective design exception requires desktop and mobile visual review; no functional or numeric gate is waived.
8282

83-
Latest completed candidate: exact `b533c80a128a85c6e2072de3bc011a09d4a97cc7`, [CI run 37032546228](https://github.com/managedcode/KeyLoad/actions/runs/37032546228). Build, format, governance and analyzer/source-inventory checks passed on all three operating systems. Real RF3 SDK/MCP catalog and queue parity, non-consuming inspection, physical-node snapshots and actual HTTP counters passed. The complete run failed: slash-equivalent static routes made the shell return HTTP 500, browser navigation could not start, and authorization/queue fixtures violated existing epoch/time contracts. Source repairs and stronger GET/HEAD/browser assertions await a new exact-SHA run; there is no successful browser screenshot receipt yet. Shared MCP discovery oracle, native logging lifecycle, process recovery and comparison failures are tracked independently and cannot count as successful qualification.
83+
Latest completed candidate: exact `1bee2609ff0de620640f304e2e42eb2859716646`, [CI run 37036628601](https://github.com/managedcode/KeyLoad/actions/runs/37036628601). Build, format, governance and analyzer/source-inventory checks passed on all three operating systems. Every OS passed 805/805 unit tests, including 13/13 AdminDashboard cases, zero skipped. All 6 RF3 AdminDashboard API cases passed, including exact shell GET/HEAD/redirect/auth protection, SDK/MCP catalog/queue parity, physical observations and persisted revocation/expiry. The browser passed shell/connection, overlap, reduced motion, background suspension and catalog navigation before failing the first document-row wait. Its UI sent an invalid empty AST projection; the source repair uses the existing standard wildcard selection and strengthens the actual seeded row/title assertion. No browser PNG was produced; full browser qualification awaits the repaired exact-SHA run. Three independent EventStreams canonical-JSON oracle failures, process recovery and comparison gates also keep the complete workflow failed.
84+
85+
The previous exact `b533c80a128a85c6e2072de3bc011a09d4a97cc7`, [CI run 37032546228](https://github.com/managedcode/KeyLoad/actions/runs/37032546228), exposed slash-equivalent routes and fixture epoch/time defects; those repairs are now qualified by the latest candidate. Native logging lifecycle and complete 50-tool discovery regressions also pass in the latest candidate. Actual receipts are retained under ignored `artifacts/qualification/admin-dashboard/37036628601/`.
8486

8587
The earlier exact `49a5b6054843800e20e333ddaa28fa96d79dd294`, [CI run 37029344985](https://github.com/managedcode/KeyLoad/actions/runs/37029344985), stopped before runtime tests at compiler/analyzer errors; later source fixes compile. Downloaded candidate receipts are retained under ignored `artifacts/qualification/admin-dashboard/37032546228/`. Root thresholds require numeric coverage, but no MTP/TUnit collector or baseline is configured: coverage remains an open gate. No local tests were executed. ADR-051 remains Accepted while required qualification is incomplete.

‎docs/Features/ClientApi.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ dependency patch, broad exception fallback, trusted caller role or timeout chang
152152
|---|---|---|
153153
| REQ-CLIENT-004: supported typed operations і capabilities дзеркалять canonical server contracts | AC-CLIENT-004: existing document/event/queue/group/graph/series/query/search/feed/admin calls повертають typed values/outcomes; unsupported capability/version дає явну помилку; equivalent query adapters дають однаковий result/authority | Existing `SqlJsonAndCSharpUseTheSameAuthorizedHttpQueryContract` у [ClusterTests](../../tests/KeyLoad.IntegrationTests/ClusterTests.cs), [QueryAdapterTests](../../tests/KeyLoad.UnitTests/QueryAdapterTests.cs); operation-manifest parity expansion PLANNED |
154154
| REQ-CLIENT-005: retry/error/cancellation зберігають stable command identity та unknown outcome | AC-CLIENT-005: transient disconnect після committed write не спричиняє другу logical operation; same ID/content replay стабільний, different payload conflict; typed errors, cancellation, bounded decode/disposal зберігають caller semantics без fabricated success | Existing `ReplicatedAtomicBatchSurvivesLeaderProcessKillAndMinorityRejectsWrites` у ClusterTests; transport edge/error cases з AC-MP-009 PLANNED/GitHub pending |
155-
| REQ-CLIENT-006: official MCP SDK adapter виконує ті самі authorized operations | AC-CLIENT-006 and AC-MCP-001–008: real official MCP C# SDK caller на Docker RF3 має operation/result/error/cancellation parity з .NET SDK; invalid/forged/revoked grants та unsupported calls fail before effects; search/storage coverage включено лише після owning capability implementation | Source IntegrationTests `Features/ClientApi/` MCP parity/adversarial suite; [ADR-039](../ADR/ADR-039-official-mcp-agent-api.md) accepted stateless `/mcp`, version-one 47-operation source catalog including ten ADR-038 BlobStorage operations and bounded admission contract; runtime pending |
155+
| REQ-CLIENT-006: official MCP SDK adapter виконує ті самі authorized operations | AC-CLIENT-006 and AC-MCP-001–008: real official MCP C# SDK caller на Docker RF3 має operation/result/error/cancellation parity з .NET SDK; invalid/forged/revoked grants та unsupported calls fail before effects; search/storage coverage включено лише після owning capability implementation | Source IntegrationTests `Features/ClientApi/` MCP parity/adversarial suite; [ADR-039](../ADR/ADR-039-official-mcp-agent-api.md) accepted stateless `/mcp`, version-one 50-operation source catalog including ten ADR-038 BlobStorage operations, three read-only ADR-051 AdminDashboard operations and bounded admission contract; runtime pending |
156156
| REQ-CLIENT-007: simple agent/worker API має bounded capability та processing contract | AC-CLIENT-007: PLANNED versioned agent calls користуються тим самим persisted principal, typed operations, quotas і outcome semantics; queue worker stale lease/duplicate handler, empty input та cancellation не дають unauthorized/duplicate effects | Existing processing semantics у [MessagingTests](../../tests/KeyLoad.UnitTests/MessagingTests.cs); agent surface tests PLANNED після ADR-039 acceptance |
157157

158158
MCP і agent surface required; accepted contracts, exact names and wrappers are in

‎docs/Features/EventStreams.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,16 @@ Preserve all existing range/policy/budget/cancellation and fixture lifetime case
6868
This is test-only input repair: ADR-035/041/039 and the canonical batch contract
6969
are sufficient, with no product/API/data boundary change or separate ADR. Lead
7070
reviews/builds/formats and qualifies complete exact-SHA GitHub unit/RF3 suites.
71+
72+
TASK-AD-E2 preserves REQ/AC-EVENT-004/005/006 and AC-MCP-002/005/007 after
73+
run37032546228 at exactb533c80 fails three RF3 cases at byte-exact EventData
74+
expectations. The existing production contract canonicalizes JSON payload/header
75+
property order; SDK/MCP bytes already agree, while the fixture expects unsorted
76+
producer bytes. One worker owns only IntegrationTests/Features/EventStreams/
77+
McpEventStreamScenario.cs and McpEventStreamTokens.cs. Keep unsorted InputEvents
78+
for actual append and handcrafted independent canonical ExpectedEvents for the
79+
unchanged exact equality, identity, sequence, paging, retry and security assertions.
80+
Do not compute expectations through production normalization or weaken comparisons.
81+
ADR-035/039 remain sufficient for this test-only oracle correction; no product,
82+
schema, authority or transport contract changes. Lead owns integration/delivery
83+
and exact-SHA GitHub qualification; local tests remain prohibited.

‎docs/implementation/status.json‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,14 +1222,14 @@
12221222
],
12231223
"manualDesignReview": "desktop_1280x720_and_mobile_390x844_disconnected_real_shell_inspected_2026_10_02_only_subjective_design",
12241224
"localTestsExecuted": false,
1225-
"qualification": "candidate_build_format_governance_analyzers_pass_RF3_catalog_queue_node_and_http_observation_pass_shell_browser_fixture_repairs_pending_exact_source_requalification",
1225+
"qualification": "805_unit_and_13_dashboard_unit_pass_each_OS_all_6_RF3_admin_API_pass_browser_invalid_AST_projection_repair_pending_exact_source_requalification",
12261226
"coverage": "required_thresholds_preserved_collector_and_actual_result_not_yet_available",
12271227
"candidateRun": {
1228-
"id": 37032546228,
1229-
"sha": "b533c80a128a85c6e2072de3bc011a09d4a97cc7",
1230-
"url": "https://github.com/managedcode/KeyLoad/actions/runs/37032546228",
1231-
"conclusion": "failure_27_of_36_RF3_pass_no_skips_three_dashboard_observation_tests_pass_shell_500_browser_not_started_test_epoch_and_clock_repairs_unqualified",
1232-
"artifacts": "artifacts/qualification/admin-dashboard/37032546228/"
1228+
"id": 37036628601,
1229+
"sha": "1bee2609ff0de620640f304e2e42eb2859716646",
1230+
"url": "https://github.com/managedcode/KeyLoad/actions/runs/37036628601",
1231+
"conclusion": "failure_805_of_805_unit_each_OS_13_dashboard_unit_each_OS_all_6_RF3_admin_API_pass_browser_row_wait_error_and_three_EventStreams_oracle_failures_no_skips",
1232+
"artifacts": "artifacts/qualification/admin-dashboard/37036628601/"
12331233
},
12341234
"baselineRun": {
12351235
"id": 37028314087,

‎src/KeyLoad.Server/Features/AdminDashboard/Assets/browsing.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ function fetchData(kind, cursor) {
162162
query:{
163163
collection:resource.name,
164164
alias:null,
165-
projection:[],
165+
projection:[{path:Config.wildcard, alias:Config.wildcard}],
166166
filter:null,
167167
order:[],
168168
limit:Config.rows,

‎src/KeyLoad.Server/Features/AdminDashboard/Assets/constants.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export const Config = Object.freeze({
44
pageSize:50,
55
rows:25,
66
astVersion:1,
7+
wildcard:'*',
78
zero:0,
89
one:1,
910
unauthenticated:401,

‎tests/KeyLoad.IntegrationTests/Features/AdminDashboard/AdminDashboardBrowserTests.cs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ internal sealed class AdminDashboardBrowserTests(ClusterFixture fixture)
1212
private const string SelectCollections = "document.querySelector('button[data-view=collections]').click();true";
1313
private const string ResourcesLoaded = "document.querySelector('#resource-list')?.textContent.includes('dashboard-documents')===true";
1414
private const string SelectResource = "(()=>{const button=[...document.querySelectorAll('#resource-list button')].find(item=>item.textContent.includes('dashboard-documents'));button.click();return true;})()";
15-
private const string RowsLoaded = "document.querySelector('#data-table')?.textContent.includes('document-1')===true";
15+
private const string RowsLoaded = "document.querySelector('#data-title')?.textContent==='dashboard-documents'"
16+
+ "&&document.querySelectorAll('#data-table tbody tr').length===1"
17+
+ "&&document.querySelector('#data-table')?.textContent.includes('document-1')===true";
1618
private const string InjectionAbsent = "window.dashboardInjection!==true";
1719
private const string FocusVisible = "(()=>{const refresh=document.getElementById('refresh');refresh.focus();return document.activeElement===refresh;})()";
1820

‎tests/KeyLoad.IntegrationTests/Features/EventStreams/McpEventStreamScenario.cs‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace KeyLoad.IntegrationTests.Features.EventStreams;
88
/// <param name="Partition">The unique configured tenant partition.</param>
99
internal sealed record McpEventStreamScenario(PartitionRef Partition)
1010
{
11-
/// <summary>Gets the immutable typed events appended by this scenario.</summary>
12-
internal static ImmutableArray<EventData> ExpectedEvents { get; } =
11+
/// <summary>Gets the immutable producer events with deliberately unsorted payload and header JSON.</summary>
12+
internal static ImmutableArray<EventData> InputEvents { get; } =
1313
[
1414
new(McpEventStreamTokens.EventIdCreated, McpEventStreamTokens.EventType,
1515
McpEventStreamTokens.InitialPayload, McpEventStreamTokens.InitialHeaders,
@@ -28,6 +28,17 @@ internal sealed record McpEventStreamScenario(PartitionRef Partition)
2828
CausationId: McpEventStreamTokens.CausationIdShipped)
2929
];
3030

31+
/// <summary>Gets the independent handcrafted canonical persisted event oracle.</summary>
32+
internal static ImmutableArray<EventData> ExpectedEvents { get; } =
33+
[
34+
InputEvents[0] with { PayloadJson = McpEventStreamTokens.CanonicalInitialPayload,
35+
HeadersJson = McpEventStreamTokens.CanonicalInitialHeaders },
36+
InputEvents[1] with { PayloadJson = McpEventStreamTokens.CanonicalPaidPayload,
37+
HeadersJson = McpEventStreamTokens.CanonicalPaidHeaders },
38+
InputEvents[2] with { PayloadJson = McpEventStreamTokens.CanonicalShippedPayload,
39+
HeadersJson = McpEventStreamTokens.CanonicalShippedHeaders }
40+
];
41+
3142
/// <summary>Gets the canonical stream identity configured by the scenario.</summary>
3243
internal StreamRef Stream => new(Partition, McpEventStreamTokens.StreamSet,
3344
McpEventStreamTokens.StreamId, McpEventStreamTokens.StreamGeneration);
@@ -55,7 +66,7 @@ await McpCallerAssertions.SdkSuccessAsync(await client.ConfigureResourceAsync(Gu
5566
/// <param name="commandId">The caller-owned retry identity.</param>
5667
/// <returns>The actual typed public batch command.</returns>
5768
internal CommandRequest AppendCommand(Guid commandId) => new(commandId, Partition,
58-
[new AppendEvents(McpEventStreamTokens.StreamSet, McpEventStreamTokens.StreamId, ExpectedEvents,
69+
[new AppendEvents(McpEventStreamTokens.StreamSet, McpEventStreamTokens.StreamId, InputEvents,
5970
ExpectedStreamRevision.NoStream, McpEventStreamTokens.StreamGeneration)]);
6071

6172
/// <summary>Builds a public bounded stream read at the supplied exclusive revision.</summary>

‎tests/KeyLoad.IntegrationTests/Features/EventStreams/McpEventStreamTokens.cs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ internal static class McpEventStreamTokens
2020
internal const string InitialHeaders = "{\"source\":\"checkout\",\"sequence\":1}";
2121
internal const string PaidHeaders = "{\"source\":\"billing\",\"sequence\":2}";
2222
internal const string ShippedHeaders = "{\"source\":\"fulfillment\",\"sequence\":3}";
23+
internal const string CanonicalInitialPayload = "{\"private\":\"mcp-private-event-canary\",\"status\":\"created\"}";
24+
internal const string CanonicalPaidPayload = "{\"private\":\"mcp-private-event-canary\",\"status\":\"paid\"}";
25+
internal const string CanonicalShippedPayload = "{\"private\":\"mcp-private-event-canary\",\"status\":\"shipped\"}";
26+
internal const string CanonicalInitialHeaders = "{\"sequence\":1,\"source\":\"checkout\"}";
27+
internal const string CanonicalPaidHeaders = "{\"sequence\":2,\"source\":\"billing\"}";
28+
internal const string CanonicalShippedHeaders = "{\"sequence\":3,\"source\":\"fulfillment\"}";
2329
internal const string CorrelationId = "mcp-event-correlation";
2430
internal const string CausationIdCreated = "mcp-event-cause-created";
2531
internal const string CausationIdPaid = "mcp-event-cause-paid";

0 commit comments

Comments
 (0)