{"verdict":"FAIL","findings":[{"severity":"P1","file":"scripts/health/dashboard_v5/source_status.py","line":177,"reason":"Source status counts every unclassified item directly and ignores the grouped review action log. Consequently, groups marked irrelevant or not assignable have zero open entries in the mapping contract but continue to contribute to the source-status review count and Today action indefinitely. The same code reports zero reviews when nutrition rows exist but the score table is absent, although the grouped contract treats those rows as unassigned.","fix":"Derive the nutrition review count from the same grouped review contract used by the bundle/API, or implement an equivalent query that honors latest exact-group actions and all documented open/terminal states. Add regressions proving irrelevant/not-assignable groups clear source status and an absent score table reports unassigned entries."},{"severity":"P2","file":"scripts/health/dashboard_v5/nutrition_mapping_review.py","line":198,"reason":"Exact alias recommendations are labeled with source \"exact_local_alias\", but the method expression checks for \"local_alias\". The emitted method is therefore always \"sighi_reference\". The worker then skips its exact-alias validation, so an alias removed or changed after preview can still be accepted as a generic canonical-rule assignment.","fix":"Emit \"local_alias\" whenever the recommendation came from an exact alias, and retain \"sighi_reference\" only for direct canonical rules. Add a preview-to-worker regression where the alias changes or disappears and require the action to fail closed."},{"severity":"P2","file":"scripts/health/dashboard_v5/nutrition_mapping_review.py","line":135,"reason":"Rules and aliases are stored in dictionaries keyed by case-folded exact identity, but the database uniqueness constraints are case-sensitive. Multiple catalog rows or aliases can therefore collapse to one identity and silently overwrite each other according to unspecified query order, allowing an arbitrary conflicting rule to become a recommendation or catalog entry.","fix":"Detect duplicate normalized rule and alias identities explicitly. If their canonical target, score, or provenance differs, suppress the recommendation and mark affected groups as conflict; also reject or omit ambiguous catalog entries. Add reversed-insertion-order tests to prove deterministic fail-closed behavior."},{"severity":"P2","file":"scripts/health/dashboard_v5/contracts.py","line":330,"reason":"The bundle validator accepts mapping summaries without validating most field types, non-negativity, coverage range, or consistency with the complete mapping-review rows. Only open_entries is compared with mapping_open_count, so malformed total, verified, conflict, deferred, group-count, or coverage values can pass validation and be rendered as authoritative summary data.","fix":"Validate every summary field and recompute total entries, verified entries, open entries, conflict/deferred groups, total groups, and coverage from mapping_review. Require exact agreement, including the defined zero-entry coverage behavior."},{"severity":"P2","file":"scripts/health/dashboard_v5/contracts.py","line":35,"reason":"The grouped builder intentionally returns every exact group, but the embedded bundle rejects more than 100 groups. The documented current inventory is already close to this bound, so a small number of new distinct groups will make dashboard regeneration fail rather than presenting the complete review.","fix":"Define a scalable contract: either raise the bound to a justified database-level maximum or keep only bounded summary data in the bundle and load paginated groups through the API. Add a bundle-generation test above the current 100-group threshold."},{"severity":"P3","file":"scripts/health/dashboard_v5/read_api.py","line":4593,"reason":"The mapping endpoint passes parse_query an allowlist containing only status, while _nutrition_mapping_queue reads and validates a search parameter. Any client request using the implemented search contract is rejected as an unknown parameter before the search code runs.","fix":"Include search in the endpoint query allowlist and add API tests for valid search, duplicate search parameters, control characters, and overlength values."}]}