fix(section-manager): skip candidates without a usable image instead of erroring (HNT-2757) - #396
fix(section-manager): skip candidates without a usable image instead of erroring (HNT-2757)#396mmiermans wants to merge 1 commit into
Conversation
…of erroring (HNT-2757) ML sends ~2,800 section-item candidates/day with no usable image_url. Each one threw a typia assert error (TypeGuardError on $input.imageUrl) that was logged as ERROR, captured in Sentry, and counted as a failure -- even though a missing image is an expected, non-actionable condition. - Treat a missing/empty image_url as an expected skip (info log, counted as "skipped", not "failed") rather than throwing downstream. - Stop pre-validating a present image via the pocket-image-cache proxy. That proxy returns false negatives for directly-fetchable images (e.g. ilsole24ore.com returns 200 directly but 500 through the proxy), so it dropped valid items. It is also redundant with curated-corpus-api, which fetches and uploads the image itself; genuine fetch failures now surface there (HNT-2758). Images remain required: candidates without one are skipped, not created.
|
Claude finished @mmiermans's task in 1m 26s —— View job Code review: PR #396 — skip image-less candidates instead of erroring
Overall this is a well-reasoned, well-tested fix. The root-cause analysis in the description is thorough, the change is scoped tightly to section-manager, and the tests cover the new behavior (null image, empty-string image, and the Correctness ✅
Minor / optional
TestsThe test updates look correct and cover the important cases: mapper returns Nice work — the trade-off (proxy false-negatives recovered vs. genuine unfetchable images shifting to HNT-2758) is clearly documented and reasonable. |
Plan Result (section-manager-lambda-cdk-production)
Change Result (Click me) # aws_lambda_function.section-manager-sqs-lambda_D7365DAE will be updated in-place
~ resource "aws_lambda_function" "section-manager-sqs-lambda_D7365DAE" {
id = "SectionManagerLambda-Prod-SQS-Function"
~ qualified_arn = "arn:aws:lambda:us-east-1:996905175585:function:SectionManagerLambda-Prod-SQS-Function:94" -> (known after apply)
~ qualified_invoke_arn = "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:996905175585:function:SectionManagerLambda-Prod-SQS-Function:94/invocations" -> (known after apply)
tags = {
"app_code" = "content"
"component_code" = "content-sectionmanagerlambda"
"env_code" = "prod"
"environment" = "Prod"
"service" = "SectionManagerLambda"
}
~ version = "94" -> (known after apply)
# (20 unchanged attributes hidden)
~ environment {
~ variables = {
- "GIT_SHA" = "692d58d478b8683256dc914fbc0f654d45ef74a0" -> null
# (5 unchanged elements hidden)
}
}
# (4 unchanged blocks hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
|
Summary
Fixes HNT-2757. The Section Manager lambda was dropping ~2,800 section-item candidates/day with a client-side
TypeGuardError: invalid type on $input.imageUrl, expect to be string, value: undefined(thrown by the typiaassertinmapSqsSectionItemToCreateApprovedItemApiInput). Because it throws before calling admin-api it is invisible to the hnt-admin-api error alert, but it is the single largest section-ingestion failure (~79% of that lambda's ~3.5% failure rate).Two root causes, both addressed:
image_url: null/empty). The ML model treatsimage_urlas optional; a strict downstream assert then turned every image-less candidate into a hard error. That is expected data, not an actionable failure.validateImageUrl, which routes through the pocket-image-cache (Thumbor) proxy and drops the item if the proxy responds non-OK.Reproduction (local
fetch)validateImageUrl)ilsole24ore.comimages are directly fetchable (200) but the proxy returns 500, sovalidateImageUrlrejected valid items. A User-Agent does not help (the failure is proxy-side). Some hosts (image.ie) block all datacenter fetches regardless.Change
image_urlmissing/empty → skip the candidate as an expected no-op (info log; counted asskipped, notfailed). Images remain required, so image-less items are still not created.validateImageUrl(pocket-image-cache) pre-check for a present image. It produced false negatives (above) and is redundant with curated-corpus-api, which performs the authoritative image fetch + S3 upload. Genuine unfetchable images (e.g. image.ie) now surface at that layer as the "Could not generate an S3 URL" error tracked by HNT-2758, instead of as a silent section-manager crash.skippedcount to the run summary log.Trade-off / scope
This converts silent, noisy section-manager drops into either (a) recovered items (proxy false-negatives like ilsole24ore) or (b) failures surfaced at the authoritative curated-corpus-api/S3 layer (HNT-2758). Net: fewer total drops and no more
TypeGuardErrornoise; a portion of genuinely-unfetchable images shifts to HNT-2758, where coarse handling of that error is being addressed separately. Scoped to section-manager; corpus-scheduler is unchanged (it sharesvalidateImageUrlbut has ~0 such failures).Test plan
npx tsc --noEmit— clean.utils.spec.ts— 23/23 pass, incl. new tests: mapper returnsnull(skip) on null/empty image;processSqsSectionDatacounts a no-image candidate as skipped, not failed.index.spec.ts— pass.validators.spec.tsare pre-existing onmain(reproduce with this branch stashed; that file imports./validators, notutils.ts; likely a typia/Node-24 local-env quirk), not introduced here.Refs: HNT-2757 (this), HNT-2758 (S3 image fetch handling).