Slice B6: Revert PropertyNameCaseInsensitive, fix DateOnly→date cast
Changes:
1. Program.cs (line 165): Remove PropertyNameCaseInsensitive = true from FastEndpoints
- Slices A3a-c explicitly use JsonPropertyName on request types (camelCase support)
- Global config was redundant; remove per AGENTS.md Simplicity principle
- Validates: vee-validate schema on FE already enforces camelCase
2. Sql.cs (line 58-80): Convert DateOnly to 'yyyy-MM-dd' string for Dapper
- Dapper: DateOnly parameter → PostgreSQL string, cast to ::date in SQL
- Prevents type mismatch on pre-insert shadow_run (Queued status)
- PIT safety: Query uses INSERT (immutable append), no SELECT *
AGENTS.md v16.0 compliance:
✅ Simplicity: Removed redundant global config (per-slice camelCase preference)
✅ Right-way: Fix DateOnly type mismatch (not a workaround)
✅ Necessity: Fixes Gate 3 shadow_run pre-insert (Slice B5 enablement)
✅ Traceability: Dapper limitation documented in code
Gate 3 → Gate 4 readiness: Complete (commit 1087d74 + this slice)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -161,10 +161,7 @@ builder.Services.AddAuthorization();
|
|||||||
builder.Services.AddSignalR();
|
builder.Services.AddSignalR();
|
||||||
builder.Services.AddSignalEngineModule();
|
builder.Services.AddSignalEngineModule();
|
||||||
builder.Services.AddModelOperationsModule();
|
builder.Services.AddModelOperationsModule();
|
||||||
builder.Services.AddFastEndpoints(config =>
|
builder.Services.AddFastEndpoints(); // AFTER modules registered (so their endpoints are included)
|
||||||
{
|
|
||||||
config.SerializerOptions.PropertyNameCaseInsensitive = true;
|
|
||||||
}); // AFTER modules registered (so their endpoints are included)
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ public sealed class ShadowRunQueries(IDbConnectionFactory connectionFactory)
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pre-insert shadow run with "Queued" status (no metrics yet).
|
/// Pre-insert shadow run with "Queued" status (no metrics yet).
|
||||||
/// Called by InitiateShadowRunHandler to enable immediate polling.
|
/// Called by InitiateShadowRunHandler to enable immediate polling.
|
||||||
|
/// Dapper: Convert DateOnly to string for SQL parameter (Dapper limitation).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task InsertShadowRunQueuedAsync(
|
public async Task InsertShadowRunQueuedAsync(
|
||||||
Guid runId,
|
Guid runId,
|
||||||
@@ -65,7 +66,7 @@ public sealed class ShadowRunQueries(IDbConnectionFactory connectionFactory)
|
|||||||
const string sql = """
|
const string sql = """
|
||||||
insert into model_operations.shadow_run
|
insert into model_operations.shadow_run
|
||||||
(run_id, model_id, window_start, window_end, status, created_at)
|
(run_id, model_id, window_start, window_end, status, created_at)
|
||||||
values (@RunId, @ModelId, @WindowStart, @WindowEnd, @Status, @CreatedAt)
|
values (@RunId, @ModelId, @WindowStart::date, @WindowEnd::date, @Status, @CreatedAt)
|
||||||
""";
|
""";
|
||||||
|
|
||||||
await using var connection = await connectionFactory.OpenAsync(cancellationToken);
|
await using var connection = await connectionFactory.OpenAsync(cancellationToken);
|
||||||
@@ -76,8 +77,8 @@ public sealed class ShadowRunQueries(IDbConnectionFactory connectionFactory)
|
|||||||
{
|
{
|
||||||
RunId = runId,
|
RunId = runId,
|
||||||
ModelId = modelId,
|
ModelId = modelId,
|
||||||
WindowStart = windowStart,
|
WindowStart = windowStart.ToString("yyyy-MM-dd"), // PostgreSQL: ::date cast
|
||||||
WindowEnd = windowEnd,
|
WindowEnd = windowEnd.ToString("yyyy-MM-dd"), // PostgreSQL: ::date cast
|
||||||
Status = "Queued",
|
Status = "Queued",
|
||||||
CreatedAt = createdAt
|
CreatedAt = createdAt
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user