From 5101eb5c7329765c9a43075619dcfc9059e05710 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 15 Jun 2026 15:49:03 +0200 Subject: [PATCH] Fix API count decoding --- Application/Helper/ApiRateLimit.hs | 4 ++-- Application/Helper/TypeRegistry.hs | 8 ++++---- workplans/ADHOC-2026-06-15.md | 29 +++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 workplans/ADHOC-2026-06-15.md diff --git a/Application/Helper/ApiRateLimit.hs b/Application/Helper/ApiRateLimit.hs index 4d3636a..a68efee 100644 --- a/Application/Helper/ApiRateLimit.hs +++ b/Application/Helper/ApiRateLimit.hs @@ -27,7 +27,7 @@ checkRateLimitAndLog :: checkRateLimitAndLog consumer endpoint method = do -- Check rate limit: requests in last 60 seconds rows1 <- sqlQuery - "SELECT COUNT(*) FROM api_request_log \ + "SELECT COUNT(*)::int FROM api_request_log \ \WHERE api_consumer_id = ? AND requested_at >= NOW() - INTERVAL '60 seconds'" (Only consumer.id) let reqCount = case rows1 of @@ -43,7 +43,7 @@ checkRateLimitAndLog consumer endpoint method = do -- Check daily quota rows2 <- sqlQuery - "SELECT COUNT(*) FROM api_request_log \ + "SELECT COUNT(*)::int FROM api_request_log \ \WHERE api_consumer_id = ? AND requested_at >= ? - INTERVAL '1 day'" (consumer.id, consumer.quotaResetsAt) let quotaUsed = case rows2 of diff --git a/Application/Helper/TypeRegistry.hs b/Application/Helper/TypeRegistry.hs index 221d95b..ff8cee4 100644 --- a/Application/Helper/TypeRegistry.hs +++ b/Application/Helper/TypeRegistry.hs @@ -12,7 +12,7 @@ validateWidgetType :: Text -> IO (Either Text ()) validateWidgetType name = do rows <- sqlQuery - "SELECT COUNT(*) FROM widget_type_registry WHERE name = ? AND status = 'active'" + "SELECT COUNT(*)::int FROM widget_type_registry WHERE name = ? AND status = 'active'" (Only name) case rows of [Only (n :: Int)] | n > 0 -> pure (Right ()) @@ -24,7 +24,7 @@ validateEventType :: Text -> IO (Either Text ()) validateEventType name = do rows <- sqlQuery - "SELECT COUNT(*) FROM event_type_registry WHERE name = ? AND status = 'active'" + "SELECT COUNT(*)::int FROM event_type_registry WHERE name = ? AND status = 'active'" (Only name) case rows of [Only (n :: Int)] | n > 0 -> pure (Right ()) @@ -36,7 +36,7 @@ validateAnnotationCategory :: Text -> IO (Either Text ()) validateAnnotationCategory name = do rows <- sqlQuery - "SELECT COUNT(*) FROM annotation_category_registry WHERE name = ? AND status = 'active'" + "SELECT COUNT(*)::int FROM annotation_category_registry WHERE name = ? AND status = 'active'" (Only name) case rows of [Only (n :: Int)] | n > 0 -> pure (Right ()) @@ -48,7 +48,7 @@ validatePolicyScope :: Text -> IO (Either Text ()) validatePolicyScope name = do rows <- sqlQuery - "SELECT COUNT(*) FROM policy_scope_registry WHERE name = ? AND status = 'active'" + "SELECT COUNT(*)::int FROM policy_scope_registry WHERE name = ? AND status = 'active'" (Only name) case rows of [Only (n :: Int)] | n > 0 -> pure (Right ()) diff --git a/workplans/ADHOC-2026-06-15.md b/workplans/ADHOC-2026-06-15.md new file mode 100644 index 0000000..f8026d8 --- /dev/null +++ b/workplans/ADHOC-2026-06-15.md @@ -0,0 +1,29 @@ +--- +id: ADHOC-2026-06-15 +type: workplan +title: "Ad hoc Inter-Hub production fixes" +domain: custodian +repo: inter-hub +status: active +owner: codex +created: "2026-06-15" +updated: "2026-06-15" +--- + +# Ad hoc Inter-Hub production fixes + +## Fix COUNT decode failures in v2 bootstrap endpoints + +```task +id: ADHOC-2026-06-15-T01 +status: progress +priority: high +``` + +Production Ops Hub bootstrap exposed a PostgreSQL/Haskell type mismatch in +the v2 API helpers. `COUNT(*)` returns `bigint`, while the helper code decoded +the result as `Int`, causing `UnexpectedColumnTypeStatementError` in widget +type validation and API request log rate-limit checks. + +Fix the count queries so widget creation and authenticated hub-registry reads +work through the documented v2 bootstrap API.